Mail apps warn users when a mail server presents a self-signed or mismatched certificate, and other mail servers can't verify your server either. Installing a trusted SSL certificate on Postfix and Dovecot fixes both. This guide uses a free Let's Encrypt certificate for the mail hostname.
Before you start
- A mail hostname such as
mail.example.comwith an A record to your server (and matching PTR). - Certbot installed and port 80 reachable (or DNS-01 validation).
- MX records pointing to
mail.example.com.
Note: On cPanel servers, mail service certificates are managed in WHM → Service Configuration → Manage Service SSL Certificates and AutoSSL can cover the hostname. Use this guide for self-managed Postfix/Dovecot.
Get the certificate
- If a web server runs on the host:
sudo certbot certonly --webroot -w /var/www/html -d mail.example.com - If not:
sudo certbot certonly --standalone -d mail.example.com
Files: /etc/letsencrypt/live/mail.example.com/fullchain.pem and privkey.pem. You can add -d imap.example.com -d smtp.example.com if users connect with those names.
Configure Postfix
In /etc/postfix/main.cf:
smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_tls_security_level = may
smtpd_tls_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
smtp_tls_security_level = may
smtpd_tls_auth_only = yesmayon port 25 offers STARTTLS without forcing it – required for internet mail.- Port 587 (submission) should use
smtpd_tls_security_level=encryptinmaster.cf; port 465 (smtps) usessmtpd_tls_wrappermode=yes. smtpd_tls_auth_only = yesstops passwords being sent before TLS.
Reload: sudo postfix check && sudo systemctl reload postfix.
Configure Dovecot
In /etc/dovecot/conf.d/10-ssl.conf:
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
ssl_prefer_server_ciphers = noThe < tells Dovecot to read the file contents. Reload: sudo systemctl reload dovecot.
Reload services after renewal
Create /etc/letsencrypt/renewal-hooks/deploy/mail.sh:
#!/bin/sh
systemctl reload postfix dovecotMake it executable (chmod +x) and test with sudo certbot renew --dry-run.
Test each port
- SMTP STARTTLS:
openssl s_client -connect mail.example.com:25 -starttls smtp - Submission:
openssl s_client -connect mail.example.com:587 -starttls smtp - SMTPS:
openssl s_client -connect mail.example.com:465 - IMAPS:
openssl s_client -connect mail.example.com:993
Look for Verify return code: 0 (ok) and the right certificate subject.
Troubleshooting
- Mail app still warns: users connect with a hostname not on the certificate (for example the bare domain). Tell them to use
mail.example.comor add names to the certificate. - Permission denied reading the key: Postfix and Dovecot read keys as root at start-up; check
/etc/letsencrypt/archivepermissions weren't changed. - Old certificate served after renewal: the deploy hook didn't run – reload services manually and check the hook.
FAQ: SSL for mail servers
Do I need separate certificates for SMTP and IMAP?
No. One certificate for the mail hostname works for both.
Should port 25 require TLS?
No. Some sending servers don't support it; use may, and MTA-STS for stricter inbound policies.
Can I use a wildcard certificate?
Yes, a *.example.com certificate covers mail.example.com.
