Back to blog
Tools··10 min read·WillItInbox Team

SMTP Ports 25 vs 465 vs 587: Which One Should You Actually Use?

SMTP port 587 vs 465 vs 25 explained: relay vs submission roles, why ISPs block port 25, RFC 8314 implicit TLS, port 2525 fallback, and a decision table.

smtp port 587 vs 465 vs 25Email deliverability

Use port 587 with STARTTLS for almost everything. Port 587 is the standard message submission port — your app authenticating to an email service or your server handing mail to your own MTA. Port 465 (implicit TLS) is an equally valid modern alternative per RFC 8314. Port 25 is for server-to-server relay only and is blocked outbound by nearly every cloud provider and ISP. Port 2525 is a non-standard fallback some ESPs offer when 587 is firewalled.

That's the answer. The rest of this post is why — and what breaks when you pick wrong, because the failure mode is usually a silent timeout, not an error.

First, understand the two roles: relay vs submission

Every SMTP connection is one of two things, and the port choice follows from which:

  • Relay: one mail server delivering to another organization's mail server, based on MX records. Gmail delivering your email to a recipient's corporate Exchange box is relay. Relay happens on port 25, always has, and requires no authentication — the receiving server accepts mail addressed to its own domains from anyone.
  • Submission: a client (your app, your marketing platform, Outlook on someone's laptop) handing a message to its own mail server or ESP for onward delivery. Submission requires authentication (SMTP AUTH, usually a username/password or API-derived credential) and happens on 587 or 465.

The confusion starts because both use the same protocol. The wire format is identical; the port signals the role, and the role determines the security expectations. Submission ports assume an authenticated client and encrypt credentials in transit. Relay port 25 assumes nothing — it was designed for open server-to-server exchange in a trustier era.

When you configure an app to send via SendGrid, Amazon SES, Mailgun, your Google Workspace account, or your own Postfix relay, you are doing submission, full stop. The receiving side will accept 25, but that's because it's a server — not because you should connect there.

Why port 25 is blocked almost everywhere

Outbound port 25 is the single most abused network path on the internet. A compromised VM or infected laptop can spray spam directly at the world's MX servers without touching any authenticated gateway. So the infrastructure industry responded with blanket blocks:

  • Cloud providers: AWS blocks outbound 25 on EC2 by default; you can request removal via a support form, and they evaluate use case before lifting it. Google Cloud blocks 25 outbound permanently on standard VMs — no exception process for SMTP to arbitrary hosts. Azure has blocked outbound 25 for most subscription types since 2017-2018 era, with limited exceptions for certain enterprise agreements.
  • Residential and business ISPs: Comcast, Spectrum, and effectively every consumer ISP block outbound 25 and have for well over a decade.
  • Hosting/VPS providers: DigitalOcean, Hetzner, OVH, and most others either block by default or throttle aggressively.

This is deliberate policy, not an accident, and it won't change — port 25 relay is where spam botnets live. The consequence for you: if your app is configured to connect to your ESP on port 25 and you deploy to a cloud VM, the connection will hang and time out. No RST packet, no error — just silence, because the block is a packet drop. This is the #1 cause of "email worked on my laptop, broken in production" tickets.

If you genuinely need outbound 25 (you're running your own MTA doing relay), request the unblock from your provider and be prepared to justify it. And note that running relay also means you need proper reverse DNS (PTR records) matching your HELO hostname, or receivers will reject you regardless of port.

Port 587: the submission default

Port 587 is the IANA-registered message submission port, defined back in RFC 2476 (1998) and reaffirmed by RFC 8314 in 2018. The connection starts in plaintext, the client issues STARTTLS to upgrade to TLS, then authenticates inside the encrypted session:

S: 220 smtp.example-esp.com ESMTP ready
C: EHLO app.yourcompany.com
S: 250-smtp.example-esp.com
S: 250-STARTTLS
S: 250-AUTH LOGIN PLAIN
C: STARTTLS
S: 220 2.0.0 Ready to start TLS
    <TLS handshake happens here — everything below is encrypted>
C: EHLO app.yourcompany.com
S: 250-AUTH LOGIN PLAIN
C: AUTH PLAIN <base64 credentials>
S: 235 2.7.0 Authentication successful

The critical rule: credentials must never cross the wire before STARTTLS completes. Any sane client library enforces this (most refuse to AUTH on an unencrypted 587 session unless you explicitly disable the check). If you ever see a config telling you to allow plaintext auth on 587, that's a red flag.

Use 587 when your app talks to an ESP's SMTP endpoint, when your own Postfix/Exchange accepts mail from internal services, and when any mail client submits outbound mail. It's the default because it works through nearly every firewall — outbound 587 is almost never blocked.

Port 465: implicit TLS, back from the dead

Port 465 has a weird history. It was briefly assigned to "SMTPS" (SMTP over implicit SSL) in the 1990s, then the assignment was revoked and 587-with-STARTTLS became the standard. For years, 465 was officially "deprecated" but universally supported anyway — every ESP and every client library kept it alive.

Then RFC 8314 (2018) formally reversed course: it re-legitimized implicit TLS on 465 as a preferred submission mechanism, on the grounds that implicit TLS is simpler to secure correctly. With implicit TLS, the TLS handshake happens immediately on connect, before any SMTP bytes are exchanged. There is no plaintext phase, no upgrade step, and therefore no possibility of a downgrade or of accidentally sending credentials pre-encryption:

C: <connects to smtp.example-esp.com:465>
    <TLS handshake happens immediately — before any SMTP commands>
S: 220 smtp.example-esp.com ESMTP ready
C: EHLO app.yourcompany.com
S: 250-AUTH LOGIN PLAIN
C: AUTH PLAIN <base64 credentials>
S: 235 2.7.0 Authentication successful

Every major ESP supports 465 alongside 587. Functionally for submission they're equivalent; 465 is arguably the safer default because misconfiguration (forgetting to require STARTTLS) can't weaken it. The full mechanics — and why the STARTTLS upgrade is strip-able in the relay context — are covered in STARTTLS vs SSL/TLS for email.

Port 2525: the non-standard fallback

2525 is not an IANA assignment — it's a convention several ESPs (SparkPost popularized it; others followed) offer for environments where outbound 587 and 465 are both blocked. This happens in locked-down corporate networks and some managed hosting panels that only permit "web" ports and a small allowlist.

Treat 2525 as a last resort, not a preference. It works, it supports the same STARTTLS or implicit TLS as the standard ports, but it's only as available as your specific ESP makes it — check their docs before assuming.

Decision table: which port for which scenario

ScenarioPortTLS modeNotes
App → ESP SMTP endpoint (SendGrid, SES, Mailgun, etc.)587 or 465STARTTLS / implicit465 preferred if your library handles it cleanly
Server → your own Postfix/Exchange relay587STARTTLS (required)Authenticated submission; restrict by IP too
Your MTA → recipient's MX (relay)25STARTTLS (opportunistic)The only correct use of outbound 25
Local dev against a real ESP587STARTTLSSame as production; don't special-case dev
Local dev against Mailpit/Mailhog sandbox1025 (or its port)noneLocal only, never in prod configs
Corporate network blocking 587/4652525STARTTLS/implicitIf your ESP offers it

One adjacent note: if your app-to-ESP path is available, the HTTP API is often the better submission channel entirely — no port concerns, better error semantics, easier retries. The trade-offs are laid out in SMTP vs API email sending.

Config snippets you'll actually paste

Postfix as an authenticated relayhost client (587)

# /etc/postfix/main.cf
relayhost = [smtp.example-esp.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt

smtp_tls_security_level = encrypt — not may — is the line that matters. may permits cleartext fallback; encrypt refuses.

Nodemailer (587 with required STARTTLS)

js
const transport = nodemailer.createTransport({
  host: "smtp.example-esp.com",
  port: 587,
  secure: false,              // false = STARTTLS upgrade, not implicit TLS
  requireTLS: true,           // refuse to send if STARTTLS fails
  auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
});

Nodemailer (465 implicit TLS)

js
const transport = nodemailer.createTransport({
  host: "smtp.example-esp.com",
  port: 465,
  secure: true,               // true = implicit TLS from connect
  auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
});

Python smtplib (both modes)

python
import smtplib

# 587 + STARTTLS
with smtplib.SMTP("smtp.example-esp.com", 587) as s:
    s.starttls()              # raises if the server won't upgrade
    s.login(user, password)
    s.send_message(msg)

# 465 implicit TLS
with smtplib.SMTP_SSL("smtp.example-esp.com", 465) as s:
    s.login(user, password)
    s.send_message(msg)

Firewall / security group rules

# AWS security group — outbound
587/tcp  0.0.0.0/0   # submission, STARTTLS
465/tcp  0.0.0.0/0   # submission, implicit TLS
# do NOT open outbound 25 unless you run your own relay MTA
# ufw on a Linux app server
ufw allow out 587/tcp
ufw allow out 465/tcp

What breaks when you choose wrong

  • 25 for submission from a cloud VM: silent timeout. Your app hangs until the connection timeout fires — often 60–120 seconds per message, destroying throughput. No log line tells you why. Check telnet smtp.your-esp.com 25 from the box; if it hangs, you're blocked.
  • 25 to an ESP from anywhere: some ESPs accept it, but your unauthenticated-looking connection patterns and lack of enforced TLS invite filtering. Just don't.
  • 587 without requiring TLS: works, but if your library doesn't enforce STARTTLS and the connection is interfered with, credentials and mail can go plaintext. Set requireTLS / smtp_tls_security_level = encrypt.
  • 465 with `secure: false` semantics (or vice versa): the client waits for a server greeting that never comes (or vice versa) — another hang. Match the port to the TLS mode.
  • Relay on 25 from a host without PTR/HELO alignment: deliveries to Gmail and Microsoft get rejected or junked. Port choice was never the whole story — see the reverse DNS guide.

When misconfiguration does produce an actual SMTP error rather than a timeout, the code tells you which layer failed — the SMTP error codes explainer decodes the 4xx/5xx responses you'll see.

Verify the whole path, not just the port

Getting the connection open is step one. Whether your mail is properly authenticated, correctly formatted, and likely to land in the inbox is a separate question. Send a real message through your configured path to WillItInbox's free deliverability tester — you'll get a 0–100 score across 70+ checks including TLS negotiation, SPF/DKIM/DMARC alignment, and header sanity, so you can confirm the config end to end rather than trusting that "the port connected." And if you're auditing which MX hosts and ports a domain accepts for relay, the MX lookup tool shows the record set and priorities in one query.

Port choice is only one line in the config. Once the connection path is right, the sender compliance checker verifies the rest of your sending setup — authentication alignment, unsubscribe headers, and the other bulk-sender requirements — so a working port isn't hiding a broken policy layer.

Frequently asked questions

Sources reviewed

Factual review: June 13, 2026 by WillItInbox Editorial.

Keep reading