NewHalo Edge 3 is here: HTTP/3 everywhere and 42 edge locations.Learn more
Docs / Email servers

Secure Postfix with TLS

Email servers8 min readUbuntu 24.04 LTS

Without encryption, passwords and messages travel as readable text between servers. This article gets a free TLS certificate with certbot, makes Postfix encrypt connections, and opens the submission port (587) so your mail app can send mail with a password over an encrypted connection.

Before you begin

  • Postfix and Dovecot installed (see the Postfix main.cf and Dovecot articles). Dovecot provides the password check that submission uses.
  • The DNS A record for mail.example.com pointing at your server, and the record must already resolve. Certificates cannot be issued for a name that does not point to the server yet.
  • Ports 80, 587 and 993 reachable from the internet. Port 80 is only needed briefly when the certificate is issued and renewed.
  • A sudo user on the server.

Step 1: Get a certificate with certbot

certbot is a free, open-source tool that requests certificates from a free certificate authority and renews them automatically. The --standalone method briefly starts a small web server on port 80 to prove you control the name, so port 80 must be free.

sudo apt update
sudo apt install -y certbot
sudo ufw allow 80/tcp
sudo certbot certonly --standalone -d mail.example.com

certbot asks for an email address for expiry warnings and whether you agree to the terms. When it succeeds you will see a line like this:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/mail.example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/mail.example.com/privkey.pem

The fullchain.pem file is the public certificate, and privkey.pem is the private key. Keep the key private and never copy it into a public place.

Step 2: Let Postfix use the certificate

Point Postfix at the two files and set how strictly it requires encryption. The value may means "use encryption when the other side supports it," which is right for mail arriving from other servers. Your own clients get a stricter rule in the next step.

sudo postconf -e 'smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem'
sudo postconf -e 'smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem'
sudo postconf -e 'smtpd_tls_security_level = may'
sudo postconf -e 'smtp_tls_security_level = may'
sudo postconf -e 'smtpd_tls_auth_only = yes'

smtpd_tls_auth_only makes sure a password is never accepted over an unencrypted connection.

Step 3: Connect Postfix to Dovecot for logins

Postfix does not check passwords itself. It asks Dovecot through a Unix socket that Dovecot creates inside Postfix's spool folder. Tell Postfix to use it, then add a listener in Dovecot.

sudo postconf -e 'smtpd_sasl_type = dovecot'
sudo postconf -e 'smtpd_sasl_path = private/auth'
sudo postconf -e 'smtpd_sasl_auth_enable = yes'
sudo nano /etc/dovecot/conf.d/99-local.conf

Add this block at the end of the file. It creates the socket with ownership that lets Postfix use it:

service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = postfix
  }
}

Step 4: Enable the submission port

Port 587 is where mail apps send messages. It must require encryption and a login. Ubuntu ships this service commented out, so you define it with postconf -M and set its options with -P.

sudo postconf -M 'submission/inet=submission inet n - y - - smtpd'
sudo postconf -P 'submission/inet/syslog_name=postfix/submission'
sudo postconf -P 'submission/inet/smtpd_tls_security_level=encrypt'
sudo postconf -P 'submission/inet/smtpd_sasl_auth_enable=yes'
sudo postconf -P 'submission/inet/smtpd_recipient_restrictions=permit_sasl_authenticated,reject'
sudo ufw allow 587/tcp
sudo ufw allow 25/tcp
sudo ufw allow 993/tcp

The encrypt setting refuses logins over plain text on port 587. The recipient rule allows only logged-in senders to use this port. Port 25 receives mail from other servers, and 993 is the encrypted IMAP port from the Dovecot article.

Step 5: Reload and verify

Restart both services, then confirm that the expected ports are listening.

sudo postfix check
sudo systemctl restart postfix dovecot
sudo ss -tlnp | grep -E ':(25|587|993)\s'

You should see three listening lines, one each for ports 25, 587 and 993. Then test the submission port. The server should offer STARTTLS, and after encryption starts it should offer AUTH:

openssl s_client -starttls smtp -connect mail.example.com:587

Type EHLO test and press Enter after the TLS handshake. Look for a Verify return code: 0 (ok) line near the top, and for 250-AUTH PLAIN LOGIN in the reply. Type QUIT to exit.

Step 6: Renew the certificate automatically

Certificates expire after a few months. The certbot package installs a timer that renews them, but Postfix and Dovecot must reload to use the new files. A small deploy hook takes care of that.

sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh
#!/bin/sh
systemctl reload postfix dovecot
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh
sudo certbot renew --dry-run

A dry run tests the renewal without changing your real certificate. A successful run ends with Congratulations, all simulated renewals succeeded.

Careful: port 587 accepts logins from anyone on the internet who has a valid password, so use long, unique passwords for every mailbox. Never disable smtpd_tls_auth_only to get a quick connection working.

Troubleshooting

  • certbot fails with a connection error on port 80: check that the DNS record points at this server and that sudo ss -tlnp | grep :80 shows nothing else using the port. Then retry.
  • Mail app says authentication failed: confirm the Dovecot socket exists with sudo ls -l /var/spool/postfix/private/auth, and that the username and password are correct.
  • Mail app refuses to connect on 587: the app may be set to use SSL on the wrong port. Port 587 uses STARTTLS, so choose that option in the app.
  • Postfix reports a certificate error: run sudo postconf smtpd_tls_cert_file smtpd_tls_key_file and check the paths exist.

Next steps

Your server now encrypts connections and lets your mail app send with a login. The next articles help other mail servers trust what you send: SPF lists which servers may send for your domain, DKIM signs your messages, and DMARC ties the two together.

Something not working? Chat or email our support team and we will help you get unstuck.

Contact support