Nodemailer

nodemailer ssl3_get_record wrong version number

The Nodemailer ssl3_get_record wrong version number error is an OpenSSL port/TLS mismatch. Use secure:false on port 587 (STARTTLS) and secure:true on 465.

Updated Jul 1, 2026

The short answer

This isn't a Nodemailer bug — it's an OpenSSL handshake error meaning your client sent a TLS handshake to a port that expected plaintext first. It almost always comes from setting secure: true on port 587. Fix it by using secure: false for port 587 (STARTTLS) and secure: true only for port 465 (implicit TLS).

What causes the Nodemailer "ssl3_get_record wrong version number" error?

This error is raised by OpenSSL (Node's TLS layer), not by Nodemailer itself. The full message looks like error:1408F10B:SSL routines:ssl3_get_record:wrong version number on OpenSSL 1.x, or error:0A00010B:SSL routines::wrong version number on OpenSSL 3.x (current in Node 18+, including Node 22 LTS) — the numeric code and function name differ between OpenSSL versions, but the underlying cause is identical. It means your code opened a TLS handshake immediately, but the server on that port replied with a plaintext SMTP greeting (e.g. 220 smtp.example.com ESMTP). OpenSSL tries to read the TLS record version field out of that plaintext, gets a nonsense value, and aborts.

In Nodemailer terms, this is almost always a mismatch between the secure flag and the port:

  • Port 465 uses implicit TLS — encryption starts the instant you connect, so it needs secure: true.
  • Port 587 (and 25) uses STARTTLS — the connection opens in plaintext and is upgraded after the STARTTLS command, so it needs secure: false.

Setting secure: true on port 587 makes Nodemailer try to negotiate TLS against a server that is still speaking plaintext — producing the wrong-version-number error. (Both ports are valid and encrypted per RFC 8314; 465 is not deprecated.)

Note: secure: false does not send mail in the clear. As the Nodemailer SMTP docs state, the connection is still upgraded to TLS via STARTTLS once connected.

How do I fix the wrong version number error?

1. Match secure to your port. This resolves the vast majority of cases.

const nodemailer = require("nodemailer");
// Port 587 — STARTTLS
const transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
secure: false, // upgrade later with STARTTLS
auth: { user: "username", pass: "password" },
});
// Port 465 — implicit TLS
const transporterImplicit = nodemailer.createTransport({
host: "smtp.example.com",
port: 465,
secure: true, // TLS from the first byte
auth: { user: "username", pass: "password" },
});

Nodemailer's default for secure is false, and it auto-sets true when port is 465. If you're hitting this error you've likely overridden that.

2. Force the STARTTLS upgrade if your provider requires encryption. With secure: false, add requireTLS: true so the send fails loudly rather than falling back to plaintext:

const transporter = nodemailer.createTransport({
host: "smtp.example.com",
port: 587,
secure: false,
requireTLS: true,
auth: { user: "username", pass: "password" },
});

3. Rule out the inverse mismatch. If you set secure: false on port 465, you'll see a hang or a different TLS error because the server never sends a plaintext greeting. Switch to secure: true.

4. Check for a proxy / wrong host. The same OpenSSL error appears if host actually points at a plain HTTP service, a load balancer terminating TLS elsewhere, or a corporate proxy. Confirm the endpoint really is an SMTP server on the port you specified, e.g. openssl s_client -starttls smtp -connect smtp.example.com:587.

What about the "use Hotmail/Outlook service" advice?

For Outlook/Hotmail, smtp-mail.outlook.com listens on port 587 with STARTTLS, so secure: false is correct there too. Microsoft has also been retiring Basic Auth for Exchange Online/Office 365 — if auth fails after fixing the port, you may need OAuth2 rather than a username/password.

Common mistakes

  • This error is not caused by an outdated Nodemailer version — upgrading the package will not fix a port/secure mismatch.
  • The legacy nodemailer.createTransport("SMTP", {...}) signature was removed in Nodemailer v1. Use the single-object form shown above.

FAQ

Common questions

No. With secure: false on port 587, Nodemailer still upgrades the connection to TLS using STARTTLS once connected, as the official Nodemailer docs state. To guarantee the upgrade happens, add requireTLS: true so the send fails rather than falling back to plaintext.

One API, every provider

Stop debugging raw provider errors

Courier connects to your email, SMS, and push providers, handles retries and failover, and surfaces delivery errors in plain language.

Reply-code definitions per RFC 8314 §3.3, §7.3. Last reviewed Jul 1, 2026. Courier is not affiliated with third-party providers; error behavior may vary by implementation.