How to Send Emails in Node.js Using Nodemailer (Ultimate Guide)
Sending emails is a fundamental task in many web applications — from user registration confirmations to password resets, invoices, and marketing campaigns. If you’re building a Node.js app and need to send emails, Nodemailer is hands down the most popular and reliable library.
In this detailed guide, you’ll learn:
- What Nodemailer is and why it’s used
- How to install and configure Nodemailer
- How to send a simple email
- How to add attachments
- How to use HTML email templates
- How to integrate with services like Gmail, Outlook, SendGrid
- Common errors and how to fix them
- Best practices for production
By the end, you’ll have a complete understanding and a practical working setup to send emails in your Node.js projects confidently.
Let’s dive right in! 🚀
What is Nodemailer?
Nodemailer is a Node.js module that enables you to easily send emails. It’s a zero-dependency package — simple to set up and flexible enough to handle everything from basic messages to complex email services.
Key Features of Nodemailer:
- SMTP and other transport protocols supported
- Attachments support
- HTML content, embedded images
- OAuth2 authentication (for Gmail, Outlook, etc.)
- Unicode support
- Ability to send bulk or scheduled emails
It’s like having your own tiny mail server inside your app without needing to overcomplicate things.
Setting Up Your Node.js Project
Before we start sending emails, let’s set up our project.
Step 1: Initialize a Node.js Project
mkdir nodemailer-tutorial
cd nodemailer-tutorial
npm init -y
This creates a package.json
file.
Step 2: Install Nodemailer
Now, install Nodemailer:
npm install nodemailer
You’re all set to begin coding!
Sending Your First Email
Now let’s get your first email sent.
Step 1: Create a File
Create a file called sendEmail.js
.
Step 2: Basic Code to Send an Email
const nodemailer = require('nodemailer');
// Create a transporter
let transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: 'your-email@gmail.com',
pass: 'your-email-password'
}
});
// Email options
let mailOptions = {
from: 'your-email@gmail.com',
to: 'recipient@example.com',
subject: 'Hello from Node.js',
text: 'This is a test email sent from Node.js using Nodemailer.'
};
// Send email
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log('Error occurred: ', error.message);
} else {
console.log('Email sent: ', info.response);
}
});
Run it with:
node sendEmail.js
And if everything is set correctly, your email will be sent!
Important Notes on Gmail
If you’re using Gmail:
- Less secure apps access must be enabled on your account.
- Alternatively, you should use OAuth2 authentication for better security (explained later).
- Google may block sign-in attempts; you might need to create an App Password.
Understanding Nodemailer Components
Let’s break down what’s happening:
Component | Meaning |
---|---|
Transporter | A configuration that tells Nodemailer how to send emails (e.g., via Gmail SMTP). |
Mail Options | The email content: from, to, subject, text, HTML, attachments, etc. |
sendMail() | The method that actually sends the email. |
Once you understand these three, you can build any email functionality!
Sending HTML Emails
Text emails are boring! Let’s add some HTML content.
let mailOptions = {
from: 'your-email@gmail.com',
to: 'recipient@example.com',
subject: 'HTML Email Example',
html: `<h1>Hello 👋</h1><p>This is an <b>HTML email</b> sent using Nodemailer!</p>`
};
HTML allows you to style your emails however you want.
You can even add inline CSS for beautiful designs.
Adding Attachments
Need to send PDFs, images, or files?
Here’s how:
let mailOptions = {
from: 'your-email@gmail.com',
to: 'recipient@example.com',
subject: 'Sending Attachments',
text: 'Please find attached files.',
attachments: [
{
filename: 'document.txt',
path: './document.txt'
},
{
filename: 'image.png',
path: './image.png'
}
]
};
Nodemailer will handle the file encoding automatically. Easy!
Embedding Images Inside Emails (Inline Images)
Sometimes you want to show images inside the email body, not just as attachments.
Example:
let mailOptions = {
from: 'your-email@gmail.com',
to: 'recipient@example.com',
subject: 'Email with Embedded Image',
html: `<h1>Look at this image:</h1><img src="cid:unique@nodemailer.com"/>`,
attachments: [{
filename: 'image.png',
path: './image.png',
cid: 'unique@nodemailer.com' // same CID as in HTML
}]
};
This displays the image inside the email rather than as a download.
Using Email Templates
Hardcoding HTML is messy. Instead, use templating engines like Handlebars, EJS, or Pug.
Here’s a quick example using Handlebars:
Install dependencies:
npm install nodemailer-express-handlebars
Setup with Handlebars:
const hbs = require('nodemailer-express-handlebars');
const path = require('path');
transporter.use('compile', hbs({
viewEngine: {
extName: '.hbs',
partialsDir: path.resolve('./templates'),
defaultLayout: false,
},
viewPath: path.resolve('./templates'),
extName: '.hbs'
}));
let mailOptions = {
from: 'your-email@gmail.com',
to: 'recipient@example.com',
subject: 'Welcome Email',
template: 'welcome', // name of your file 'welcome.hbs'
context: {
name: 'John Doe',
company: 'NodeMailer Inc.'
}
};
In templates/welcome.hbs
:
<h1>Hello </h1>
<p>Welcome to !</p>
Dynamic, clean, and easy to maintain.
Integrating with Popular Email Services
Instead of sending directly via SMTP, you can use email providers.
Here’s a quick setup:
Gmail
(Already shown above, with service: 'gmail'
.)
Outlook
service: 'hotmail',
auth: {
user: 'your-email@hotmail.com',
pass: 'your-password'
}
SendGrid
For bulk transactional emails:
host: 'smtp.sendgrid.net',
port: 587,
auth: {
user: 'apikey',
pass: 'YOUR_SENDGRID_API_KEY'
}
More reliable than Gmail for production.
Handling Errors
When sending emails, errors can happen:
- Wrong credentials
- SMTP server unavailable
- Invalid recipient email
- Attachments missing
You should wrap sendMail()
in a try-catch
block:
async function sendEmail() {
try {
let info = await transporter.sendMail(mailOptions);
console.log('Email sent: ', info.response);
} catch (error) {
console.error('Error sending email: ', error.message);
}
}
Always validate user input too!
Common Errors and Fixes
Error | Solution |
---|---|
Invalid login |
Check your email and password or OAuth2 settings |
Connection timeout |
SMTP server unreachable; check host/port |
Blocked by Gmail |
Enable less secure apps or use App Passwords |
Self-signed certificate error |
Add tls: { rejectUnauthorized: false } in transporter |
Example adding TLS settings:
let transporter = nodemailer.createTransport({
host: 'smtp.example.com',
port: 587,
secure: false,
auth: {
user: 'your-email@example.com',
pass: 'your-password'
},
tls: {
rejectUnauthorized: false
}
});
Advanced: Sending Bulk Emails
Sending thousands of emails? Use loops + delays to avoid hitting limits:
Example:
const recipients = ['a@example.com', 'b@example.com', 'c@example.com'];
recipients.forEach((email, index) => {
setTimeout(() => {
transporter.sendMail({
from: 'your-email@gmail.com',
to: email,
subject: 'Personalized Email',
text: `Hello ${email}, this is a test.`
}, (err, info) => {
if (err) {
console.log(`Error sending to ${email}:`, err.message);
} else {
console.log(`Email sent to ${email}:`, info.response);
}
});
}, index * 2000); // 2-second delay between emails
});
This way, you won’t overwhelm the server.
Best Practices for Emailing
- Use a dedicated email service (SendGrid, Mailgun) in production.
- Validate all email inputs.
- Avoid sending sensitive information unencrypted.
- Always catch and log errors.
- If sending bulk, add delays or use services built for bulk mailing.
- Monitor your email sending rates and bounce rates.
Conclusion
Nodemailer is a simple yet powerful tool for sending emails with Node.js.
With just a few lines of code, you can integrate advanced emailing features into your app, from simple notifications to complex templated newsletters.
In this guide, you learned:
- Setting up Nodemailer
- Sending text, HTML, attachments
- Using templates
- Handling errors
- Integrating with email services
- Best practices for production
If you follow the patterns and tips shared here, you’ll be able to build reliable email services for any application.
Leave a comment