Which port does your mail really use?
It depends on who your server is talking to, and for most apps that's a mail service, not the recipient's mail server.
| Port | Who talks to whom | Sign-in | Encryption |
|---|---|---|---|
| 587 | Your app to a mail service | Username and password or key | Starts plain, then upgrades with STARTTLS |
| 465 | Your app to a mail service | Username and password or key | Encrypted from the first byte |
| 25 | One mail server to another | None | Offered between servers when both support it |
Don't agonise over 587 against 465. RFC 8314 says that if the software is correct and both sides require TLS before any mail is handed over, there's no significant security difference between them. Use the one your mail service documents.
Why do hosts keep it closed?
Because a freshly rented machine with outbound 25 open can start sending spam at once, and the damage lands on the address and its neighbours. Large clouds publish the same rule for the same reason: they generally block outbound 25 by default because of the abuse risk, and leave the authenticated route open, on 587 and in some cases 465. The anti-abuse group M3AAWG first recommended this in 2005 for residential and dynamic addresses, and still calls blocking 25 from all but a few permitted hosts an industry best practice, and Spamhaus's Policy Blocklist exists to say certain addresses should send through an authenticated submission server instead of delivering directly.
So a closed port 25 says nothing bad about a host. The real questions are whether you need it and whether you can get it opened.
What can your server reach right now?
Find out before you change anything. On Ubuntu, if nc is missing, run apt-get update && apt-get install -y netcat-openbsd as root; other systems word the result differently. Replace smtp.provider.example with your mail service's host. The last line only opens a connection to one of Gmail's mail servers and sends nothing.
nc -4 -vz -w 5 smtp.provider.example 587
nc -4 -vz -w 5 smtp.provider.example 465
nc -4 -vz -w 5 gmail-smtp-in.l.google.com 25
| You see | It means | Do this |
|---|---|---|
| succeeded | The path is open | Carry on |
| timed out | Something on the way dropped it, usually a host block on 25 | On 25, use 587 or 465, or request 25. On 587 or 465, check your own firewall and the provider's host name |
| refused | Usually the far end answered and isn't listening there, though a firewall can also reject | Check the hostname and port, then any firewall |
Pick the route that matches your app
| Route | Port 25 needed? | What you look after | Suits |
|---|---|---|---|
| App signs in to a mail service directly | No | One set of SMTP settings | One app that can retry on its own |
| Local Postfix relays to a mail service | No | A small queue on your server | Several apps, or code that shouldn't wait on the network |
| Your own mail server delivers directly | Yes | Reputation, reverse DNS, listings, spam handling | You have a reason to hold your own mail |
For a password reset or an order receipt, the middle route is usually our pick. A web request that talks to a remote mail service directly can hang or fail when that service has a bad minute. Handing the message to Postfix on the same machine is quick, and Postfix keeps retrying. Your app connects to 127.0.0.1 on port 25, and that hop never leaves the machine, so a host block doesn't touch it.
Set up a Postfix relay on 587
These steps follow Postfix's own SASL guide, for Ubuntu 24.04, as root. Replace app.example.com, smtp.provider.example and you@yourdomain.example with your own. Use the server's own hostname as the mail name, not your main domain, or Postfix will try to keep mail for that domain on the machine. Once Postfix restarts in the next step, loopback-only means nothing outside the server can use it.
if echo "postfix postfix/mailname string app.example.com" | debconf-set-selections &&
echo "postfix postfix/main_mailer_type select Internet Site" | debconf-set-selections &&
apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y postfix libsasl2-modules &&
postconf -e 'inet_interfaces = loopback-only' \
'relayhost = [smtp.provider.example]:587' \
'smtp_tls_security_level = encrypt' \
'smtp_sasl_auth_enable = yes' \
'smtp_sasl_tls_security_options = noanonymous' \
'smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd' &&
{ [ -e /etc/postfix/sasl_passwd ] || install -m 600 /dev/null /etc/postfix/sasl_passwd; }; then
echo "now add the login line"
else
echo "STOP: Postfix is not set up"
fi
Open /etc/postfix/sasl_passwd in an editor rather than echoing the password, which would leave it in your shell history. Add one line, [smtp.provider.example]:587 username:password. The brackets and port must match relayhost exactly, as Postfix's guide warns. Then build the table, restart and send yourself a message:
if [ -s /etc/postfix/sasl_passwd ] && chmod 600 /etc/postfix/sasl_passwd &&
postmap /etc/postfix/sasl_passwd && chmod 600 /etc/postfix/sasl_passwd.db &&
postfix check && systemctl restart postfix; then
printf 'From: you@yourdomain.example\nSubject: relay check\n\nHello from the server.\n' |
sendmail -f you@yourdomain.example you@yourdomain.example
sleep 10; journalctl -t postfix/smtp -n 5 --no-pager
else
echo "STOP: check the login file and Postfix before sending"
fi
You're looking for status=sent. If the block says -- No entries -- or shows no status= line, run grep postfix/smtp /var/log/mail.log | tail -n 5. If mail sits in the queue, postqueue -p shows why. Three things usually catch people:
- Only 465 on offer? Use
:465in bothrelayhostand the login line, runpostconf -e 'smtp_tls_wrappermode = yes', then run the second block again to rebuild the table and restart. Without that setting Postfix waits for a greeting that never comes. - The From address is refused. Most mail services accept only domains you've verified with them, so
root@your hostname usually won't pass. Set a real sender in your app. - It arrives, in spam. Open the original message and read
Authentication-Results. You want SPF and DKIM to pass, which comes from the DNS records your mail service gave you.
What if you really do need port 25?
Then you're running a mail server, and the port is the easy part. On a Cloud VPS, ask us to open it in chat or a ticket. Say that it's for your own mail server and which domain it serves. Before you send the first message, get these right:
- Reverse DNS. Gmail's rules for all senders ask for valid forward and reverse DNS, and the name on the address must resolve back to it. On whole servers you edit this from the dashboard. The Cloud VPS page doesn't list it among its controls, so raise it in the same message as port 25.
- SPF or DKIM, and TLS. Gmail asks for at least one of those two for all senders, plus a TLS connection. Set up both, and DMARC too.
- Listings. Check the address at check.spamhaus.org, which Spamhaus names as the only place for Policy Blocklist removals. It says a single static address that's a real outbound mail server, assigned to you, with proper forward and reverse DNS, can be removed there, if the network's policy allows it.
- IPv6. Your machine has IPv6 as well, and mail can leave over it. Give that address its own reverse DNS, or set
inet_protocols = ipv4in Postfix and restart it, until you have.
A new address also has no sending record, so no host can promise the inbox. Our mailcow guide goes through the rest of running a full mail system.
The server class that fits
| Option | Port 25 | Choose it when |
|---|---|---|
| Cloud VPS | Outbound 25 closed on new machines, opened on request; 465 and 587 open from day one | Your app sends through a mail service |
| Custom dedicated server | Open from day one | Mail is a main job of the machine (tell us when you order) |
| Web hosting | Not your concern, there's no server to run | You want a website and email and nothing to look after |
On whole servers the closing rule is narrow. If one of your addresses is listed for actually sending spam, outbound 25 on that one address closes for 30 days. A listing against a whole range, or a policy listing, never triggers it. Addresses there are checked against public blocklists before you get them and swept afterwards, and a listed one is swapped. If you just need people at your domain to have mailboxes, see email on your own domain first.
Questions people ask
- Can I deliver mail over another port if 25 is closed?
- Not directly to other people's mail servers, because they accept delivery on 25. What you can do is hand mail over 587 or 465 to a service that delivers it for you, which is the relay in this guide.
- If I use a mail service, does my VPS need reverse DNS?
- Not for that mail. The service's servers make the final delivery, so their addresses are the ones receivers judge. Your job is the SPF and DKIM records for your domain.
- Does this apply to receiving mail too?
- What's described here is outbound. If you want to receive mail on the server you're running a mail server, so mention that when you ask us about port 25.