Skip to main content

Nodemailer

Send emails from Node.js - easy as cake!

Nodemailer is the most popular email sending library for Node.js. It makes sending emails straightforward and secure, with zero runtime dependencies to manage.

Install with npm
npm install nodemailer
Looking for a complete email gateway solution?

EmailEngine is a self-hosted email gateway that provides REST API access to IMAP and SMTP accounts, webhooks for mailbox changes, and advanced features like OAuth2, delayed delivery, open and click tracking, bounce detection, and more.

Why Nodemailer?

  • Zero runtime dependencies - everything you need is included in a single, well-maintained package.
  • Security focused - designed to avoid remote code execution vulnerabilities that have affected other Node.js email libraries.
  • Full Unicode support - send messages with any characters, including emoji.
  • Cross-platform - works identically on Linux, macOS, and Windows with no native addons required (ideal for cloud environments like Azure).
  • HTML and plain-text emails - send rich HTML emails with automatic plain-text fallbacks.
  • Attachments and embedded images - easily include files and inline images in your messages.
  • Built-in TLS/STARTTLS encryption - secure connections are handled automatically.
  • Multiple transports - send via SMTP, Sendmail, Amazon SES, streams, and more.
  • DKIM signing and OAuth2 authentication - enterprise-ready email authentication.
  • Proxy support - route email through proxies for restricted network environments.
  • Plugin API - extend functionality with custom plugins for advanced message processing.
  • Ethereal.email integration - generate test accounts instantly for local development and testing.

Requirements

  • Node.js v6.0.0 or later (examples using async/await require Node.js v8.0.0 or later).

No additional system libraries, services, or build tools are needed.

Quick start

Sending an email with Nodemailer involves three simple steps:

  1. Create a transporter - Configure your SMTP server or another supported transport method.
  2. Compose your message - Define the sender, recipient(s), subject, and content.
  3. Send the email - Call transporter.sendMail() with your message options.

Create a transporter

A transporter is an object that handles the connection to your email service and sends messages on your behalf. You create one transporter and reuse it for all your emails.

const nodemailer = require("nodemailer");

// Create a transporter using SMTP
const transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
secure: false, // use STARTTLS (upgrade connection to TLS after connecting)
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});

The createTransport(transport[, defaults]) function returns a reusable transporter instance.

ParameterType / Description
transportObject, String, or Plugin. Pass a configuration object (as shown above), a connection URL (for example, "smtp://user:pass@smtp.example.com:587"), or an already-configured transport plugin.
defaultsObject (optional). Default values that are automatically merged into every message sent through this transporter. Useful for setting a consistent from address or custom headers.
Reuse your transporter

Create the transporter once when your application starts and reuse it for all emails. Creating a new transporter for each message wastes resources because each transporter opens network connections and may perform authentication.

Other transport types

  • SMTP - see the SMTP guide for the full list of configuration options.
  • SES - send via Amazon Simple Email Service using the SES transport.
  • Sendmail - pipe messages to the local sendmail binary using the sendmail transport.
  • Stream/JSON - generate RFC 822 messages as streams or JSON for testing using the stream transport.
  • Plugins - Nodemailer can send emails through any transport that implements the send(mail, callback) interface. See the transport plugin documentation for details.

Verify the connection (optional)

Before sending emails, you can verify that Nodemailer can connect to your SMTP server. This is useful for catching configuration errors early.

try {
await transporter.verify();
console.log("Server is ready to take our messages");
} catch (err) {
console.error("Verification failed:", err);
}

Send a message

Once you have a transporter, send an email by calling transporter.sendMail(message[, callback]).

try {
const info = await transporter.sendMail({
from: '"Example Team" <team@example.com>', // sender address
to: "alice@example.com, bob@example.com", // list of recipients
subject: "Hello", // subject line
text: "Hello world?", // plain text body
html: "<b>Hello world?</b>", // HTML body
});

console.log("Message sent: %s", info.messageId);
// Preview URL is only available when using an Ethereal test account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
} catch (err) {
console.error("Error while sending mail:", err);
}

Parameters

ParameterDescription
messageAn object containing the email content and headers. See Message configuration for details.
callback(optional) A function with signature (err, info) => {}. If omitted, sendMail returns a Promise.

Response object

The info object returned on success contains:

PropertyDescription
messageIdThe Message-ID header value assigned to the email.
envelopeAn object containing the SMTP envelope addresses (from and to).
acceptedAn array of recipient addresses that the server accepted.
rejectedAn array of recipient addresses that the server rejected.
rejectedErrorsAn array of error objects for each rejected recipient, with details about the rejection reason.
pendingWith the direct transport: addresses that received a temporary failure.
responseThe final response string received from the SMTP server.
Partial success

When a message has multiple recipients, it is considered sent as long as at least one recipient address was accepted by the server. Check the rejected array to see which addresses failed.

Error handling

try {
const info = await transporter.sendMail(message);
console.log("Message sent:", info.messageId);

if (info.rejected.length > 0) {
console.warn("Some recipients were rejected:", info.rejected);
}
} catch (err) {
switch (err.code) {
case "ECONNECTION":
case "ETIMEDOUT":
console.error("Network error - retry later:", err.message);
break;
case "EAUTH":
console.error("Authentication failed:", err.message);
break;
case "EENVELOPE":
console.error("Invalid recipients:", err.rejected);
break;
default:
console.error("Send failed:", err.message);
}
}

See the Error reference for a complete list of error codes.

Transporter events

The transporter emits events you can listen for:

EventDescription
idleEmitted when a pooled transporter has capacity to accept more messages.
errorEmitted when a transport-level error occurs (for example, a connection failure).
tokenEmitted when a new OAuth2 access token is generated. Useful for persisting tokens.
// Listen for OAuth2 token updates
transporter.on("token", (token) => {
console.log("New access token for %s:", token.user, token.accessToken);
});

Source and License

Nodemailer is open source software, licensed under the MIT No Attribution (MIT-0) license. This means you can use it freely in any project without attribution requirements. Browse the source code on GitHub.


Made with love by Andris Reinman. Logo by Sven Kristjansen.