Node.js Send an Email - Complete Email Implementation Guide
Sending emails is a common requirement in web applications for notifications, confirmations, newsletters, and more. Node.js provides several libraries and methods to implement email functionality effectively.
Email Libraries for Node.js
Popular Email Libraries
- Nodemailer - Most popular and feature-rich
- EmailJS - Client-side email sending
- SendGrid - Cloud-based email service
- Mailgun - Transactional email service
- AWS SES - Amazon Simple Email Service
Using Nodemailer
Installation
npm install nodemailer
Basic Email Setup
const nodemailer = require('nodemailer');
// Create transporter
const transporter = nodemailer.createTransporter({
service: 'gmail',
auth: {
user: '[email protected]',
pass: 'your-app-password' // Use App Password for Gmail
}
});
// Email options
const mailOptions = {
from: '[email protected]',
to: '[email protected]',
subject: 'Test Email',
text: 'This is a test email from Node.js'
};
// Send email
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Email sent:', info.response);
}
});
SMTP Configuration
const nodemailer = require('nodemailer');
// SMTP configuration
const transporter = nodemailer.createTransporter({
host: 'smtp.gmail.com',
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: '[email protected]',
pass: 'your-app-password'
},
tls: {
rejectUnauthorized: false
}
});
// Alternative SMTP configurations
const gmailConfig = {
service: 'gmail',
auth: {
user: '[email protected]',
pass: 'your-app-password'
}
};
const outlookConfig = {
host: 'smtp-mail.outlook.com',
port: 587,
secure: false,
auth: {
user: '[email protected]',
pass: 'your-password'
}
};
const yahooConfig = {
host: 'smtp.mail.yahoo.com',
port: 587,
secure: false,
auth: {
user: '[email protected]',
pass: 'your-app-password'
}
};
HTML Emails
Basic HTML Email
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransporter({
service: 'gmail',
auth: {
user: '[email protected]',
pass: 'your-app-password'
}
});
const mailOptions = {
from: '[email protected]',
to: '[email protected]',
subject: 'Welcome to Our Service',
html: `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: #007acc; color: white; padding: 20px; text-align: center; }
.content { padding: 20px; background: #f9f9f9; }
.button { display: inline-block; padding: 10px 20px; background: #007acc; color: white; text-decoration: none; border-radius: 5px; }
.footer { text-align: center; padding: 20px; color: #666; font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Welcome to Our Service!</h1>
</div>
<div class="content">
<h2>Hello there!</h2>
<p>Thank you for signing up for our service. We're excited to have you on board!</p>
<p>Here's what you can do next:</p>
<ul>
<li>Complete your profile</li>
<li>Explore our features</li>
<li>Connect with other users</li>
</ul>
<p style="text-align: center;">
<a href="https://example.com/dashboard" class="button">Get Started</a>
</p>
</div>
<div class="footer">
<p>© 2024 Our Company. All rights reserved.</p>
<p>If you didn't sign up for this service, please ignore this email.</p>
</div>
</div>
</body>
</html>
`
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Email sent:', info.response);
}
});
Email Templates
// Email template function
function createWelcomeEmail(user) {
return `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: #007acc; color: white; padding: 20px; text-align: center; }
.content { padding: 20px; background: #f9f9f9; }
.button { display: inline-block; padding: 10px 20px; background: #007acc; color: white; text-decoration: none; border-radius: 5px; }
.footer { text-align: center; padding: 20px; color: #666; font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Welcome ${user.name}!</h1>
</div>
<div class="content">
<h2>Hello ${user.name}!</h2>
<p>Thank you for signing up for our service. We're excited to have you on board!</p>
<p>Your account details:</p>
<ul>
<li><strong>Email:</strong> ${user.email}</li>
<li><strong>Username:</strong> ${user.username}</li>
<li><strong>Signup Date:</strong> ${new Date().toLocaleDateString()}</li>
</ul>
<p style="text-align: center;">
<a href="https://example.com/dashboard" class="button">Access Your Dashboard</a>
</p>
</div>
<div class="footer">
<p>© 2024 Our Company. All rights reserved.</p>
</div>
</div>
</body>
</html>
`;
}
// Usage
const user = {
name: 'John Doe',
email: '[email protected]',
username: 'johndoe'
};
const mailOptions = {
from: '[email protected]',
to: user.email,
subject: 'Welcome to Our Service!',
html: createWelcomeEmail(user)
};
Email with Attachments
File Attachments
const nodemailer = require('nodemailer');
const path = require('path');
const transporter = nodemailer.createTransporter({
service: 'gmail',
auth: {
user: '[email protected]',
pass: 'your-app-password'
}
});
const mailOptions = {
from: '[email protected]',
to: '[email protected]',
subject: 'Email with Attachments',
text: 'Please find the attached files.',
attachments: [
{
filename: 'document.pdf',
path: './uploads/document.pdf'
},
{
filename: 'image.jpg',
path: './uploads/image.jpg',
cid: 'unique-image-id' // For inline images
},
{
filename: 'data.txt',
content: 'This is the content of the file',
contentType: 'text/plain'
}
]
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Email sent:', info.response);
}
});
Inline Images
const mailOptions = {
from: '[email protected]',
to: '[email protected]',
subject: 'Email with Inline Images',
html: `
<h1>Hello!</h1>
<p>Here's an inline image:</p>
<img src="cid:unique-image-id" alt="Inline Image" style="max-width: 100%;">
<p>Best regards,<br>Your Team</p>
`,
attachments: [
{
filename: 'logo.png',
path: './images/logo.png',
cid: 'unique-image-id'
}
]
};
Email Service Integration
SendGrid Integration
npm install @sendgrid/mail
const sgMail = require('@sendgrid/mail');
// Set API key
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const msg = {
to: '[email protected]',
from: '[email protected]',
subject: 'Hello from SendGrid',
text: 'Hello from SendGrid!',
html: '<strong>Hello from SendGrid!</strong>'
};
sgMail.send(msg)
.then(() => {
console.log('Email sent');
})
.catch((error) => {
console.error('Error:', error);
});
Mailgun Integration
npm install mailgun-js
const mailgun = require('mailgun-js')({
apiKey: process.env.MAILGUN_API_KEY,
domain: process.env.MAILGUN_DOMAIN
});
const data = {
from: '[email protected]',
to: '[email protected]',
subject: 'Hello from Mailgun',
text: 'Hello from Mailgun!',
html: '<strong>Hello from Mailgun!</strong>'
};
mailgun.messages().send(data, (error, body) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Email sent:', body);
}
});
AWS SES Integration
npm install aws-sdk
const AWS = require('aws-sdk');
// Configure AWS SES
const ses = new AWS.SES({
region: 'us-east-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
});
const params = {
Destination: {
ToAddresses: ['[email protected]']
},
Message: {
Body: {
Html: {
Data: '<h1>Hello from AWS SES!</h1>',
Charset: 'UTF-8'
},
Text: {
Data: 'Hello from AWS SES!',
Charset: 'UTF-8'
}
},
Subject: {
Data: 'Hello from AWS SES',
Charset: 'UTF-8'
}
},
Source: '[email protected]'
};
ses.sendEmail(params, (error, data) => {
if (error) {
console.error('Error:', error);
} else {
console.log('Email sent:', data);
}
});
Complete Email Service
Email Service Class
const nodemailer = require('nodemailer');
const path = require('path');
class EmailService {
constructor() {
this.transporter = nodemailer.createTransporter({
service: 'gmail',
auth: {
user: process.env.EMAIL_USER,
pass: process.env.EMAIL_PASS
}
});
}
// Send welcome email
async sendWelcomeEmail(user) {
const mailOptions = {
from: process.env.EMAIL_USER,
to: user.email,
subject: 'Welcome to Our Service!',
html: this.createWelcomeTemplate(user)
};
try {
const info = await this.transporter.sendMail(mailOptions);
console.log('Welcome email sent:', info.messageId);
return { success: true, messageId: info.messageId };
} catch (error) {
console.error('Error sending welcome email:', error);
return { success: false, error: error.message };
}
}
// Send password reset email
async sendPasswordResetEmail(user, resetToken) {
const resetUrl = `${process.env.FRONTEND_URL}/reset-password?token=${resetToken}`;
const mailOptions = {
from: process.env.EMAIL_USER,
to: user.email,
subject: 'Password Reset Request',
html: this.createPasswordResetTemplate(user, resetUrl)
};
try {
const info = await this.transporter.sendMail(mailOptions);
console.log('Password reset email sent:', info.messageId);
return { success: true, messageId: info.messageId };
} catch (error) {
console.error('Error sending password reset email:', error);
return { success: false, error: error.message };
}
}
// Send notification email
async sendNotificationEmail(user, notification) {
const mailOptions = {
from: process.env.EMAIL_USER,
to: user.email,
subject: notification.subject,
html: this.createNotificationTemplate(user, notification)
};
try {
const info = await this.transporter.sendMail(mailOptions);
console.log('Notification email sent:', info.messageId);
return { success: true, messageId: info.messageId };
} catch (error) {
console.error('Error sending notification email:', error);
return { success: false, error: error.message };
}
}
// Send email with attachment
async sendEmailWithAttachment(recipient, subject, content, attachmentPath) {
const mailOptions = {
from: process.env.EMAIL_USER,
to: recipient,
subject: subject,
html: content,
attachments: [
{
filename: path.basename(attachmentPath),
path: attachmentPath
}
]
};
try {
const info = await this.transporter.sendMail(mailOptions);
console.log('Email with attachment sent:', info.messageId);
return { success: true, messageId: info.messageId };
} catch (error) {
console.error('Error sending email with attachment:', error);
return { success: false, error: error.message };
}
}
// Template methods
createWelcomeTemplate(user) {
return `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: #007acc; color: white; padding: 20px; text-align: center; }
.content { padding: 20px; background: #f9f9f9; }
.button { display: inline-block; padding: 10px 20px; background: #007acc; color: white; text-decoration: none; border-radius: 5px; }
.footer { text-align: center; padding: 20px; color: #666; font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Welcome ${user.name}!</h1>
</div>
<div class="content">
<h2>Hello ${user.name}!</h2>
<p>Thank you for signing up for our service. We're excited to have you on board!</p>
<p style="text-align: center;">
<a href="${process.env.FRONTEND_URL}/dashboard" class="button">Access Your Dashboard</a>
</p>
</div>
<div class="footer">
<p>© 2024 Our Company. All rights reserved.</p>
</div>
</div>
</body>
</html>
`;
}
createPasswordResetTemplate(user, resetUrl) {
return `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: #dc3545; color: white; padding: 20px; text-align: center; }
.content { padding: 20px; background: #f9f9f9; }
.button { display: inline-block; padding: 10px 20px; background: #dc3545; color: white; text-decoration: none; border-radius: 5px; }
.footer { text-align: center; padding: 20px; color: #666; font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Password Reset Request</h1>
</div>
<div class="content">
<h2>Hello ${user.name}!</h2>
<p>You requested a password reset for your account.</p>
<p>Click the button below to reset your password:</p>
<p style="text-align: center;">
<a href="${resetUrl}" class="button">Reset Password</a>
</p>
<p><strong>Note:</strong> This link will expire in 1 hour.</p>
</div>
<div class="footer">
<p>© 2024 Our Company. All rights reserved.</p>
<p>If you didn't request this, please ignore this email.</p>
</div>
</div>
</body>
</html>
`;
}
createNotificationTemplate(user, notification) {
return `
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: #28a745; color: white; padding: 20px; text-align: center; }
.content { padding: 20px; background: #f9f9f9; }
.footer { text-align: center; padding: 20px; color: #666; font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>${notification.subject}</h1>
</div>
<div class="content">
<h2>Hello ${user.name}!</h2>
<p>${notification.message}</p>
</div>
<div class="footer">
<p>© 2024 Our Company. All rights reserved.</p>
</div>
</div>
</body>
</html>
`;
}
}
module.exports = EmailService;
Express Route Integration
const express = require('express');
const EmailService = require('./EmailService');
const app = express();
const emailService = new EmailService();
// Middleware
app.use(express.json());
// Send welcome email
app.post('/send-welcome', async (req, res) => {
try {
const { user } = req.body;
const result = await emailService.sendWelcomeEmail(user);
if (result.success) {
res.json({ message: 'Welcome email sent successfully' });
} else {
res.status(500).json({ error: result.error });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Send password reset email
app.post('/send-password-reset', async (req, res) => {
try {
const { user, resetToken } = req.body;
const result = await emailService.sendPasswordResetEmail(user, resetToken);
if (result.success) {
res.json({ message: 'Password reset email sent successfully' });
} else {
res.status(500).json({ error: result.error });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Send notification email
app.post('/send-notification', async (req, res) => {
try {
const { user, notification } = req.body;
const result = await emailService.sendNotificationEmail(user, notification);
if (result.success) {
res.json({ message: 'Notification email sent successfully' });
} else {
res.status(500).json({ error: result.error });
}
} catch (error) {
res.status(500).json({ error: error.message });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Email Queue System
Using Bull Queue
npm install bull
const Queue = require('bull');
const EmailService = require('./EmailService');
// Create email queue
const emailQueue = new Queue('email processing', {
redis: {
host: 'localhost',
port: 6379
}
});
const emailService = new EmailService();
// Process email jobs
emailQueue.process('send-welcome', async (job) => {
const { user } = job.data;
return await emailService.sendWelcomeEmail(user);
});
emailQueue.process('send-password-reset', async (job) => {
const { user, resetToken } = job.data;
return await emailService.sendPasswordResetEmail(user, resetToken);
});
// Add email to queue
async function queueWelcomeEmail(user) {
await emailQueue.add('send-welcome', { user }, {
delay: 1000, // 1 second delay
attempts: 3, // Retry 3 times
backoff: 'exponential'
});
}
async function queuePasswordResetEmail(user, resetToken) {
await emailQueue.add('send-password-reset', { user, resetToken }, {
delay: 500, // 500ms delay
attempts: 2
});
}
module.exports = { emailQueue, queueWelcomeEmail, queuePasswordResetEmail };
Best Practices
1. Environment Variables
# .env
EMAIL_USER=[email protected]
EMAIL_PASS=your-app-password
SENDGRID_API_KEY=your-sendgrid-api-key
MAILGUN_API_KEY=your-mailgun-api-key
MAILGUN_DOMAIN=your-mailgun-domain
FRONTEND_URL=http://localhost:3000
2. Error Handling
const sendEmail = async (mailOptions) => {
try {
const info = await transporter.sendMail(mailOptions);
return { success: true, messageId: info.messageId };
} catch (error) {
console.error('Email error:', error);
// Handle specific errors
if (error.code === 'EAUTH') {
return { success: false, error: 'Authentication failed' };
} else if (error.code === 'ECONNECTION') {
return { success: false, error: 'Connection failed' };
} else {
return { success: false, error: 'Unknown error occurred' };
}
}
};
3. Rate Limiting
const rateLimit = require('express-rate-limit');
const emailRateLimit = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5, // limit each IP to 5 requests per windowMs
message: 'Too many email requests, please try again later'
});
app.use('/send-email', emailRateLimit);
4. Email Validation
const validator = require('validator');
const validateEmail = (email) => {
return validator.isEmail(email);
};
const sendEmail = async (recipient, subject, content) => {
if (!validateEmail(recipient)) {
throw new Error('Invalid email address');
}
// Send email logic
};
Next Steps
Now that you understand email functionality, you're ready to:
- Node.js - Events - Learn event-driven programming
- Node.js - Event Loop - Understand the event loop
- Node.js - Event Emitter - Learn custom event handling
- Node.js - Debugger - Master debugging techniques
Email Mastery Complete! You now know how to implement comprehensive email functionality in Node.js applications. Email is essential for user communication and notifications!