# Nodemailer 10: SMTP email sending from Node.js, and what the upgrade costs you

> Nodemailer is the long-standing Node.js library for composing RFC 822 messages and delivering them over SMTP. Version 10 requires Node.js 20, ships its own TypeScript types, and drops the @types/nodemailer package.

**nodemailer/nodemailer** — ✉️ Send e-mails with Node.JS – easy as cake!

- Repository: https://github.com/nodemailer/nodemailer
- Website: http://nodemailer.com/
- Stars: 17,683 · Forks: 1,434
- Language: TypeScript
- License: NOASSERTION
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/nodemailer-nodemailer

## What Nodemailer actually does, and who ends up using it

Nodemailer composes an email message and hands it to a transport. That is the whole product. The README describes it as sending emails from Node.js, and the repository topics list email, email-sender, nodemailer and rfc822, which is a fair summary of the scope: message construction plus delivery, not campaign management, contact lists or delivery analytics.

The audience follows from that scope. Backend developers who already have a Node.js process and an SMTP relay they are allowed to use. Teams that need transactional mail (password resets, receipts, notifications) sent from inside an application rather than through a third-party HTTP API. Anyone who wants the message to leave their own infrastructure.

It is not a mail server. It does not receive mail, it does not queue and retry across process restarts, and it does not tell you whether a message was opened. If you need those things you are looking at a different category of tool, and the README is explicit about one adjacent option: the project is developed by the team behind EmailEngine, a self-hosted email API that turns a Gmail, Microsoft 365 or IMAP account into a REST endpoint. The README points at it for people who would rather call an HTTP API than maintain IMAP and SMTP connections themselves. That is a useful signal about where the library's boundary sits.

## Transports, the mail composer, and where DNS fits in

The architecture visible in the repository is a mailer on top of pluggable transports. The package exports subpaths for the pieces: ./lib/mail-composer, ./lib/mailer, ./lib/addressparser, ./lib/mime-funcs, ./lib/dkim, ./lib/json-transport and ./lib/fetch, each with separate ESM and CommonJS entry points. So the MIME building, address parsing, DKIM signing and the SMTP delivery path are separable modules rather than one monolith.

Delivery over SMTP is the default story. The transport opens a connection to the configured host and port, authenticates, and sends the composed message. The README's troubleshooting section is the most informative part of the documentation about how this behaves in practice. It states that Nodemailer resolves hostnames with dns.resolve4() and dns.resolve6() rather than the system resolver, falling back to dns.lookup() only if both fail. That matters because Node.js uses c-ares for name resolution, so custom DNS routing configured at the operating system level may simply be ignored. If you have internal split-horizon DNS pointing an SMTP hostname at an internal relay, this is where it bites. The documented escape hatch is to hard code the IP address in the configuration, in which case no DNS lookup happens at all.

The README also documents the secure option with a precision that is worth repeating: secure should be true only for port 465. For every other port it should be false. Setting it to false does not disable TLS. The transport still upgrades the connection when the server supports it. Getting this backwards is a common source of connection failures.

## Installing Nodemailer 10 and sending a first message

Install with npm. The package ships both an ES module build and a CommonJS build, so either import style works. Version 10 and later require Node.js 20 or newer.

```bash
npm install nodemailer
```

The README states that Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so @types/nodemailer is no longer needed. If it is in your project, remove it to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as Mail.Options, SMTPTransport.Options and Transporter<SMTPTransport.SentMessageInfo> keep compiling, and the most used types (SendMailOptions, Transporter, SentMessageInfo, Attachment, Address) are exported from the package root.

A minimal transporter configuration, following the shape the README gives for SMTP options:

```js
let configOptions = {
    host: 'smtp.example.com',
    port: 587,
    tls: {
        rejectUnauthorized: true,
        minVersion: 'TLSv1.2'
    }
};
```

Port 587 with secure left unset is the ordinary submission setup. The tls block is what the README shows when diagnosing TLS errors, and minVersion: 'TLSv1.2' matches the floor that current Node.js releases enforce anyway.

If DNS is the problem, the README gives this alternative, which skips name resolution entirely:

```js
let configOptions = {
    host: '1.2.3.4',
    port: 465,
    secure: true,
    tls: {
        // must provide server name, otherwise TLS certificate check will fail
        servername: 'example.com'
    }
};
```

The comment in that snippet is the important part. Hard coding the IP removes the DNS lookup but also removes the hostname from the TLS handshake, so servername has to be supplied or certificate validation fails. The examples directory in the repository contains await.js, oauth2.js, custom-auth-async.js, custom-headers.js, pool-mx.js, ses.js, sendmail.js and verify.js, which is a reasonable map of what the library supports beyond the basic case.

## Where Nodemailer is the wrong tool, and the Gmail caveat

The README's Gmail answer is unusually blunt: Gmail either works well, or it does not work at all, and it is probably easier to switch to an alternative service than to fix issues with Gmail. That is the project's own position, and it should be read as a boundary rather than a bug report. If your sending strategy depends on a personal Gmail account, you are outside the path the maintainers want to support.

Cloudflare Workers is a second constrained environment. The ES module build runs there with the nodejs_compat compatibility flag, but only SMTP based transports apply. sendmail needs a child process, which Workers does not provide. The runtime also does not allow turning certificate validation off, so tls.rejectUnauthorized: false fails there with an error. Any code path that disables verification for a misconfigured relay has to be removed before that deployment.

A third limitation is structural rather than environmental. Nodemailer is a library inside your process. It has no cross-restart queue, no bounce processing, and no delivery dashboard. If a message fails because the receiving server is temporarily unavailable, the retry behaviour is whatever your code and your relay do. Teams that need durable retries, suppression lists or per-message delivery events are looking for a sending service, not a transport.

## Nodemailer compared with an HTTP sending API

The real alternative for most teams is an HTTP API that accepts a JSON payload and handles SMTP on your behalf. The README names one directly: EmailEngine, a self-hosted email API that turns a Gmail, Microsoft 365 or IMAP account into a REST endpoint, with managed OAuth2, webhooks for incoming mail and built-in sending.

The difference is where the connection lives. With Nodemailer, your process holds the SMTP connection, manages authentication, and is responsible for the retry logic around it. With an HTTP API, you make a request and something else owns the connection, the OAuth2 token refresh and the inbound webhooks. The trade-off is not quality, it is operational surface. Nodemailer gives you no vendor between your application and the relay, which is exactly what some teams want for data residency or for using an internal relay. An HTTP API removes the connection management and the OAuth2 plumbing, at the cost of a dependency and, in the hosted case, a bill.

If your blocker is specifically OAuth2 setup rather than Gmail itself, the README points at EmailEngine for handling the flow and token refresh. That is the honest framing: Nodemailer supports OAuth2 (there is an examples/oauth2.js), but you own the token lifecycle.

## Upgrade cost, licensing, and what the release cadence implies

The jump to version 10 has three concrete costs. Node.js 20 becomes the floor, so applications on older runtimes must stay on the 9.x line. The @types/nodemailer dependency becomes actively harmful and should be removed. And the published package now carries its own type definitions, which means a TypeScript project should re-run its build after upgrading rather than assuming the old declarations still resolve.

The release history is dense. v10.0.8, v10.0.9 and v10.0.10 all landed within four days of each other in September 2026, and the last push to the default branch was on 2026-09-14. Frequent patch releases on a 10.0.x line usually indicate a stream of small fixes, which is normal for a library this widely deployed, but it also means pinning to a patch version and reading the changelog before bumping is the cheaper habit. The repository keeps a CHANGELOG.md and a .release-please-config.json, so the release notes are generated and available.

On licensing, the README states Nodemailer is licensed under the MIT No Attribution license. The repository's LICENSE file is the authoritative text, and the GitHub metadata reports the licence as NOASSERTION, meaning the automated classifier could not match the file to a standard SPDX identifier. That discrepancy is worth resolving with your own legal review rather than assuming the README label settles it. MIT No Attribution removes the attribution requirement that ordinary MIT imposes, but the exact wording of the file is what governs, and this is not legal advice.

## Conclusion

Adopt Nodemailer if you run Node.js 20 or newer and want to talk SMTP directly from your own process or from a serverless runtime with nodejs_compat. Do not adopt it if you need a hosted HTTP sending API with delivery analytics, or if you are pinned to Node.js 18 and cannot move off the 9.x line. Before upgrading, verify that @types/nodemailer is removed from your dependency tree, that your SMTP credentials still authenticate, and that any tls.rejectUnauthorized: false setting is gone if you deploy to Cloudflare Workers, where it fails with an error.

## FAQ

### What is Nodemailer used for?

It sends email from Node.js applications. The README describes it as composing and sending emails, and the repository topics list email, email-sender and rfc822, so the scope is message construction plus delivery over a transport such as SMTP.

### Is Nodemailer completely free?

The README states the project is licensed under the MIT No Attribution license. The GitHub metadata reports the licence as NOASSERTION because the classifier could not match the licence file to a standard identifier, so the LICENSE file itself is what you should read.

### How do I use Nodemailer with Gmail?

The README does not give a Gmail setup walkthrough. It says Gmail either works well or does not work at all, and suggests switching to an alternative service rather than fixing Gmail issues. There is an examples/oauth2.js in the repository, and the README points at EmailEngine for teams whose blocker is the OAuth2 flow and token refresh.

### Does Nodemailer have a limit?

No sending limit is stated. The documented constraints are environmental: Node.js 20 or newer for version 10, only SMTP based transports on Cloudflare Workers, and no tls.rejectUnauthorized: false on that runtime.

### How do I install Nodemailer?

Install it with npm install nodemailer. The README states that version 10 and later require Node.js 20 or newer and ship both ES module and CommonJS builds, so both import and require work.

## Sources

- [Issues](https://github.com/nodemailer/nodemailer/issues)
- [nodemailer/nodemailer on GitHub](https://github.com/nodemailer/nodemailer)
- [Project website](http://nodemailer.com/)
- [README](https://github.com/nodemailer/nodemailer/blob/master/README.md)
- [Releases](https://github.com/nodemailer/nodemailer/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nodemailer-nodemailer
