Securing every email path with TLS: obtaining Let's Encrypt certificates via certbot, configuring smtpd_tls_cert_file and smtpd_tls_key_file in Postfix, ssl_cert and ssl_key in Dovecot, enforcing TLS on submission and IMAP, plus auto-renewing certificates so they never expire.

DNS in episode 5 determined where email goes. Now we make sure that email arrives encrypted. Without TLS, passwords and email contents cross the internet as plaintext — the equivalent of sending a credit card via postcard.
This episode covers three things: obtaining a Let's Encrypt certificate with certbot, installing it in Postfix and Dovecot, and locking down the services so TLS is truly mandatory. We'll also set up auto-renewal so certificates never expire.
There are three points that need TLS on a mail server:
Without TLS, email is still "sent" — but anyone on the path can read and modify it. In an era where major providers reject connections without TLS, this is no longer optional.
We use certificates from Let's Encrypt via certbot — free, automated, and trusted by all clients. Make sure port 80 is open for the HTTP-01 challenge:
sudo apt install -y certbot
sudo certbot certonly --standalone -d mail.example.comThe certificate will be stored at:
/etc/letsencrypt/live/mail.example.com/fullchain.pem — the full certificate chain./etc/letsencrypt/live/mail.example.com/privkey.pem — the private key.Access to these files must be restricted: sudo chmod 640 /etc/letsencrypt/live/mail.example.com/privkey.pem ensures only services running as root read it. Dovecot runs as the dovecot user, so its access must be opened — we'll cover that in the Dovecot section.
Postfix has three main certificate parameters: smtpd_tls_cert_file, smtpd_tls_key_file, and smtpd_tls_security_level. For the receiving server (port 25) and submission, the configuration is:
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 postfix reloadThe value may means TLS is offered but not mandatory — right for port 25 so old servers are still accepted. For submission (port 587), we'll raise it to encrypt in the enforcement section later. Check that TLS is active with:
postconf smtpd_tls_security_level smtpd_tls_cert_file
openssl s_client -connect mail.example.com:25 -starttls smtp -servername mail.example.comIf openssl s_client shows the line Verify return code: 0, the certificate is valid and TLS works.
Dovecot manages certificates via ssl_cert and ssl_key in conf.d/10-ssl.conf. Edit that file with your favorite editor and make sure the following lines are active:
ssl = yes
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pemNote the < sign at the start of the paths — in Dovecot syntax that means "read the file's contents", not merely use the string. A step that's often missed: give the dovecot user access to the certificate directory, because Let's Encrypt creates directories with root-only permissions:
sudo mkdir -p /etc/letsencrypt/live/mail.example.com
sudo setfacl -m u:dovecot:rX /etc/letsencrypt /etc/letsencrypt/live /etc/letsencrypt/live/mail.example.com
sudo dovecot reloadRestart and verify:
systemctl restart dovecot
openssl s_client -connect mail.example.com:993 -servername mail.example.comVerify return code: 0 means IMAPS is ready to use.
Up to this point TLS is available. Now we require it at the risky points — submission and IMAP:
sudo postconf -e 'smtpd_tls_security_level = encrypt'
sudo postconf -e 'smtpd_tls_loglevel = 1'
sudo postfix reloadencrypt rejects connections that refuse STARTTLS, so passwords never cross without encryption. In Dovecot, make sure ssl = required — not just yes:
ssl = requiredThis combination forces all clients to use TLS. What remains: modern ciphers. Restrict to TLS 1.2 and above so weak legacy protocols aren't used:
sudo postconf -e 'smtpd_tls_protocols = !SSLv2 !SSLv3 !TLSv1 !TLSv1.1'
sudo postconf -e 'smtpd_tls_mandatory_protocols = !SSLv2 !SSLv3 !TLSv1 !TLSv1.1'
sudo postfix reloadCheck the similar ssl_* settings in Dovecot (ssl_min_protocol = TLSv1.2).
Let's Encrypt certificates are valid for 90 days. The only safe way forward is automating renewal. Certbot provides --deploy-hook to reload services after renewal:
sudo certbot renew --dry-runIf the dry-run succeeds, create the reload hook. Because SMTP can't restart while email is in the queue, we only reload. Create /etc/letsencrypt/renewal-hooks/deploy/reload-mail:
#!/bin/bash
postfix reload
dovecot reloadMake it executable, then check systemctl list-timers to see the certbot.timer running twice a day — certbot only renews when less than 30 days remain, so this is safe.
Episode 6 is done. Key takeaways:
certbot certonly and stored in /etc/letsencrypt/live/.smtpd_tls_cert_file / smtpd_tls_key_file; Dovecot uses ssl_cert / ssl_key with the < prefix.encrypt / ssl = required; port 25 is fine with may.openssl s_client.All paths are now encrypted. In episode 7 we replace system users with database-managed virtual users — the foundation for multi-domain and centralized authentication for Postfix and Dovecot. See you in episode 7!