Use port 587 with STARTTLS, or 465 with implicit TLS, for sending mail from an application. Port 25 is for server-to-server relay and is blocked outbound on virtually every cloud provider, which is the reason your mail code works locally and times out in production.
The confusion here is genuine rather than manufactured, because the standards contradicted each other for two decades and the advice you find reflects whichever era the author learned it in. The ports do different jobs, and once you see which job is which the choice is not close.
Table of contents
- The four ports and what each is for
- Implicit TLS versus STARTTLS, and why 465 has the edge
- Why your mail code times out in production
- Delivery is not a port problem
- Quick reference
- How this fits the rest of the stack
- FAQ
The four ports and what each is for
Port 25 is the original SMTP port, used for relay between mail servers. When your provider’s server hands a message to the recipient’s server, it uses 25. It was never intended for applications submitting mail, and today it is blocked outbound by nearly every cloud provider and residential ISP because it was the primary channel for spam from compromised machines.
Port 587 is the submission port, defined by RFC 6409 for authenticated clients handing mail to their own server. It uses STARTTLS: the connection opens in plaintext and is upgraded to TLS before credentials are sent. This is the widely supported default.
Port 465 has an unusual history. It was assigned for SMTPS, deprecated in favour of STARTTLS, then rehabilitated by RFC 8314 in 2018, which recommends it for implicit TLS. The connection is encrypted from the first byte with no upgrade step.
Port 2525 is not a standard at all. It is a convention several providers offer as a fallback for networks that block the real ports. It works, it is widely supported, and it has no official standing.
- 25: server-to-server relay. Blocked outbound almost everywhere. Not for your application.
- 587: submission with STARTTLS. The safe default with the broadest support.
- 465: submission with implicit TLS. Preferred by RFC 8314 and slightly safer by design.
- 2525: unofficial fallback. Use when the others are blocked.
Implicit TLS versus STARTTLS, and why 465 has the edge
On 465 the TLS handshake happens immediately. There is no plaintext phase, so there is nothing to intercept before encryption is established.
On 587 the conversation starts unencrypted, the client issues STARTTLS, and the connection upgrades. The weakness is theoretical but real: an attacker positioned in the middle can strip the STARTTLS advertisement from the server’s capability list, and a client configured to permit an unencrypted fallback will proceed in the clear. This is a downgrade attack, and it is why RFC 8314 tilted back towards 465.
The mitigation on 587 is to require TLS rather than prefer it, so the client aborts instead of falling back. Every serious mail library supports this and it is often not the default.
import smtplib, ssl
ctx = ssl.create_default_context()
# Implicit TLS on 465: encrypted from the first byte.
with smtplib.SMTP_SSL("smtp.example.com", 465, context=ctx) as s:
s.login(user, password)
s.send_message(msg)
# STARTTLS on 587: upgrade, and refuse to continue without it.
with smtplib.SMTP("smtp.example.com", 587) as s:
s.ehlo()
s.starttls(context=ctx) # raises if the server will not upgrade
s.ehlo()
s.login(user, password)
s.send_message(msg)
In practice: use 465 if your provider supports it, 587 if that is what they document, and in either case verify certificates. A library configured to skip certificate validation has thrown away most of the benefit of encrypting at all.
Why your mail code times out in production
This is the most common report, and the sequence is always the same. It works on the developer’s machine, it is deployed, and sends hang until the socket times out with no error from the mail server, because no mail server was ever reached.
The cause is almost always port 25 blocked outbound. Cloud providers block it by default and generally will not unblock it. The fix is to use 587 or 465 against a mail provider that expects authenticated submission, not to appeal the block.
Confirm it in one command before changing any code.
# If this hangs, the port is blocked. A 220 greeting means it is open.
openssl s_client -starttls smtp -crlf -connect smtp.example.com:587
# Implicit TLS on 465.
openssl s_client -crlf -connect smtp.example.com:465
# Plain reachability check when you only need open or closed.
nc -zv smtp.example.com 587
The openssl form is more useful than nc because it shows the certificate and the server’s advertised capabilities, which tells you whether STARTTLS is offered at all and which authentication mechanisms it will accept.
The other frequent cause is authentication failure reported as a generic error. Many providers now require an application-specific password or a token rather than the account password, and the resulting rejection is often unhelpfully worded.
Delivery is not a port problem
Worth saying plainly, because it is where the real difficulty lies: choosing the right port gets your message to your provider. It has nothing to do with whether it lands in an inbox.
That is determined by your sending domain’s authentication records and reputation. SPF authorises which servers may send for your domain. DKIM signs messages so the recipient can verify they were not altered. DMARC tells receivers what to do when the other two fail, and where to report it.
Without all three configured, a technically perfect message sent over a correctly encrypted connection lands in spam, and the connection log will show a clean success. The ports and the deliverability are separate problems that fail in different places.
The related trap is running your own mail server on a cloud IP. Even with 25 unblocked, IP ranges belonging to cloud providers carry poor sending reputation by default, and building a good one takes months of consistent volume. For transactional mail from an application, use a provider whose entire business is maintaining that reputation.
Quick reference
- Sending from an application: port 587 with STARTTLS required, or 465 with implicit TLS.
- Connection hangs in production: assume port 25 is blocked and switch to 587 or 465.
- Both blocked by a restrictive network: try 2525 if the provider offers it.
- Verify with openssl s_client, not by guessing, and read the advertised capabilities.
- Never disable certificate verification to make an error go away.
- Configure SPF, DKIM, and DMARC before worrying about why mail is not arriving.
How this fits the rest of the stack
Mail is usually one part of an application that also has a database, a queue for retries, and logs recording which sends failed and why. Costing those pieces separately makes it easier to see where the money actually goes, since the mail provider, the service running the code, and the database are three different line items. The RunxBuild hosting calculator puts the service, database, and storage side by side, and per-deploy runtime logs are where a failed send shows up first.
Useful related references:
- Port 587: The SMTP Submission Port, and Why Your App Should Use It
- What Port is SSH: 22 (Default), How to Change, and Why
- Port 25: Why Your Host Blocks It and What to Use Instead
- Services on RunxBuild
FAQ
Which SMTP port should I use?
Port 587 with STARTTLS is the safest default because support is universal. Port 465 with implicit TLS is marginally better by design and preferred by RFC 8314. Use whichever your mail provider documents.
Why is port 25 blocked?
It was the main channel for spam from compromised machines, so cloud providers and ISPs block it outbound by default. It is intended for server-to-server relay, not for applications submitting mail, so this rarely affects legitimate use.
What is the difference between port 465 and 587?
465 encrypts the connection from the first byte with implicit TLS. 587 opens in plaintext and upgrades via STARTTLS, which is vulnerable to a downgrade attack if the client permits an unencrypted fallback. Configure 587 to require TLS.
Is port 2525 an official SMTP port?
No. It is an unofficial convention several providers offer as a fallback when standard ports are blocked. It works fine but has no standards backing, so support varies by provider.
Why does my email work locally but not in production?
Almost always outbound port 25 blocked by the hosting provider. Test with openssl s_client against the port, and switch to 587 or 465 with authentication against a mail provider.