2026年11月12日
2026年11月12日
Mail Server SSL/TLS Setup: Enable STARTTLS in Postfix and Dovecot
This article is a localized edition of the Japanese original. Read the Japanese original
To encrypt mail server traffic, you configure a server certificate in both Postfix, which handles sending, and Dovecot, which handles receiving (IMAP). This article walks through getting a Let's Encrypt certificate and enabling STARTTLS and port 465 TLS in Postfix, and IMAP TLS in Dovecot.
The steps were checked with the stock packages of Ubuntu 24.04 (Postfix 3.8, Dovecot 2.3) and Debian 13 (Postfix 3.10, Dovecot 2.4) as of October 2026. Dovecot 2.3 and 2.4 use different setting names, so both are shown.
STARTTLS vs. TLS from the start
There are two ways to encrypt mail traffic.
- STARTTLS: connect in plaintext, then switch to encryption with the
STARTTLScommand - TLS from the start (implicit TLS): use TLS immediately after the connection opens
Which one each port uses:
| Port | Purpose | Method |
|---|---|---|
| 25 | Delivery between mail servers (SMTP) | STARTTLS (encrypted if the other side supports it) |
| 587 | Sending from mail clients (submission) | STARTTLS (encryption required) |
| 465 | Sending from mail clients (submissions) | TLS from the start |
| 143 | IMAP | STARTTLS |
| 993 | IMAPS | TLS from the start |
For traffic between mail clients and the server, RFC 8314 recommends TLS from the start (465 and 993). Port 25 is normally left with optional encryption so that mail can still be delivered when the other server does not support encryption.
Prerequisites
- The A record of the mail server's hostname (
mail.example.comin this article) points to the server's IP address. - The certificate name matches the hostname in your MX record and the server name configured in mail clients.
- Postfix and Dovecot are running, and SMTP authentication for ports 587 and 465 (Dovecot SASL or similar) is already set up. If not, complete Building a mail server with Postfix and Dovecot first.
- Ports 25, 587, 465 and 993 (and 143 if needed) are open in the firewall.
Step 1: Get a certificate
Use certbot to get a certificate for mail.example.com. To obtain it, that hostname must be able to answer HTTP on port 80.
sudo apt update
sudo apt install certbot
# If no web server is using port 80 (certbot listens on port 80 temporarily)
sudo certbot certonly --standalone -d mail.example.com
# If a web server on the same machine serves mail.example.com (specify its document root)
sudo certbot certonly --webroot -w /var/www/html -d mail.example.com
When it succeeds, these files are created:
- Certificate (including intermediates):
/etc/letsencrypt/live/mail.example.com/fullchain.pem - Private key:
/etc/letsencrypt/live/mail.example.com/privkey.pem
Postfix and Dovecot read these files with root privileges at startup, so you do not need to change their permissions.
Step 2: Configure Postfix main.cf
Add the following settings to /etc/postfix/main.cf. If a setting with the same name already exists, edit that line instead (when a setting appears twice, the later one wins).
# Receiving side (when other servers or mail clients connect)
smtpd_tls_chain_files = /etc/letsencrypt/live/mail.example.com/privkey.pem, /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_mandatory_protocols = >=TLSv1.2
smtpd_tls_loglevel = 1
# Sending side (when delivering to other servers)
smtp_tls_security_level = may
smtp_tls_loglevel = 1
What each setting does:
| Setting | Meaning |
|---|---|
smtpd_tls_chain_files |
The private key and certificate files. List the private key first (Postfix 3.4 and later) |
smtpd_tls_security_level = may |
Offer STARTTLS without requiring encryption (for port 25) |
smtpd_tls_auth_only = yes |
Do not accept SMTP authentication over unencrypted connections |
smtpd_tls_mandatory_protocols |
Minimum TLS version for connections where encryption is mandatory (such as port 587 with encrypt). The >= syntax requires Postfix 3.6 or later |
smtp_tls_security_level = may |
Encrypt outgoing mail when the destination supports STARTTLS |
*_tls_loglevel = 1 |
Log TLS connections |
The default configuration on Ubuntu and Debian contains smtpd_tls_cert_file and smtpd_tls_key_file lines pointing to a self-signed certificate. Once you set smtpd_tls_chain_files, those two are ignored and a warning is logged, so delete both lines. On Postfix 3.3 or earlier, set those two to fullchain.pem and privkey.pem instead of using smtpd_tls_chain_files.
The smtpd_use_tls = yes and smtp_use_tls = yes settings often seen in older articles were replaced by smtpd_tls_security_level and smtp_tls_security_level in Postfix 2.3 and deprecated in Postfix 3.9. Remove them if they are still there.
Step 3: Enable ports 587 and 465 in Postfix master.cf
/etc/postfix/master.cf already contains commented-out entries for port 587 (submission) and port 465 (submissions). Remove the leading # to enable them. At a minimum, these lines must be active:
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_auth_only=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
submissions inet n - y - - smtpd
-o syslog_name=postfix/submissions
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
smtpd_tls_security_level=encrypt: on port 587, no commands are accepted until the connection is encryptedsmtpd_tls_wrappermode=yes: port 465 listens with TLS from the start
Lines starting with -o must begin with whitespace so that they continue the previous line. The shipped master.cf contains other -o lines as well; it is fine to leave any you do not understand commented out.
Check the configuration and apply it:
sudo postfix check
sudo postconf -n | grep tls
sudo systemctl reload postfix
Step 4: Configure Dovecot (IMAP)
The configuration file is /etc/dovecot/conf.d/10-ssl.conf. You can check the Dovecot version with dovecot --version.
For Dovecot 2.3 (Ubuntu 24.04 and others):
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_min_protocol = TLSv1.2
Dovecot 2.3 requires a < before the file name. Without <, the path string itself is treated as the certificate content, so the certificate cannot be loaded and you get an error.
For Dovecot 2.4 (Debian 13 and others):
ssl = required
ssl_server_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_server_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_min_protocol = TLSv1.2
With ssl = required, users cannot log in over unencrypted connections (either STARTTLS or port 993 is fine). Check the configuration and apply it:
sudo doveconf -n | grep ssl
sudo systemctl reload dovecot
Step 5: Reload when the certificate is renewed
The certbot package on Debian and Ubuntu includes a timer for automatic renewal. Check that it is running:
systemctl list-timers | grep certbot
Even after the certificate is renewed, Postfix and Dovecot keep using the old one until they are reloaded. Add a certbot deploy hook so that they reload only when a certificate is actually renewed.
sudo tee /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh > /dev/null << 'EOF'
#!/bin/sh
systemctl reload postfix
systemctl reload dovecot
EOF
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh
Scripts in renewal-hooks/deploy/ run when a certificate is successfully issued or renewed. You may also see advice to run sudo certbot renew --post-hook "systemctl reload postfix" by hand, but that only attempts a renewal once, at that moment; it does not set up anything recurring.
You can test the renewal flow with this command:
sudo certbot renew --dry-run
Deploy hooks are not run with --dry-run. To test the hooks too, add --run-deploy-hooks.
As of October 2026, the default lifetime of a Let's Encrypt certificate is 90 days. Let's Encrypt has announced that it will drop to 64 days from February 2027 and to 45 days from February 2028, so rely on automatic renewal rather than manual work. See also Setting up automatic certificate renewal with certbot.
Step 6: Verify that encryption works
Connect to each port with openssl s_client to check that a TLS connection can be made and that the certificate is correct. The trailing < /dev/null makes the command exit right after the connection check.
# Port 587 (STARTTLS)
openssl s_client -connect mail.example.com:587 -starttls smtp -servername mail.example.com -brief < /dev/null
# Port 465 (TLS from the start)
openssl s_client -connect mail.example.com:465 -servername mail.example.com -brief < /dev/null
# Port 25 (STARTTLS)
openssl s_client -connect mail.example.com:25 -starttls smtp -servername mail.example.com -brief < /dev/null
# Port 993 (IMAPS)
openssl s_client -connect mail.example.com:993 -servername mail.example.com -brief < /dev/null
On success you will see lines like these:
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Peer certificate: CN=mail.example.com
Verification: OK
If Verification is not OK, check that the certificate's hostname matches the name you connected to and that you specified fullchain.pem (with cert.pem the intermediate certificates are missing).
On home internet connections in Japan and elsewhere, ISPs often block outbound port 25 (OP25B, Outbound Port 25 Blocking). Test port 25 from another server.
To check whether traffic with external servers is encrypted, look at the Postfix log. With smtpd_tls_loglevel = 1 and smtp_tls_loglevel = 1, every encrypted connection is logged with a line containing TLS connection established.
# Systems with rsyslog (Ubuntu and others)
sudo grep "TLS connection established" /var/log/mail.log | tail
# Systems that log only to journald (default Debian 12 and later, etc.)
sudo journalctl -t postfix/smtpd -t postfix/smtp --since today | grep "TLS connection established"
Notes
- Encryption on port 25 is optional, "if the other side supports it." To enforce encryption between servers, use separate mechanisms such as MTA-STS (RFC 8461) or DANE (RFC 7672).
- Setting
smtpd_tls_security_level = encrypton port 25 means you can no longer receive mail from servers that do not support encryption. Do not use it on port 25 of a public mail server (the Postfix documentation also says not to use it for this purpose). - Replacing the certificate does not affect sender authentication (SPF, DKIM, DMARC). Deliverability needs to be handled separately (How to check SPF, DKIM and DMARC).
Summary
- Get the certificate for the mail server's hostname (the name used in MX and in mail client settings).
- In Postfix, set up STARTTLS on port 25 with
smtpd_tls_chain_filesandsmtpd_tls_security_level = may, and ports 587 (encrypt) and 465 (wrappermode) in master.cf. - Do not use outdated settings such as
smtpd_use_tls. - Dovecot 2.3 and 2.4 use different names for the certificate settings.
- Reload on renewal with a script in
renewal-hooks/deploy/, and verify encryption withopenssl s_clientand the logs.
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)