By Greg Nowak. Updated 13 October 2026.
A mail server change is successful when customer enquiries still arrive, password resets still go out, and staff can open their inboxes. Enabling TLS should protect those connections without disrupting them. The key decision is where to require encryption: public mail delivery, authenticated sending and mailbox access need different policies.
This guide covers an existing Postfix and Dovecot installation. If you only need to send website notifications, a managed SMTP relay may be easier to maintain. Hosting mail also means owning updates, monitoring and recovery.
Map the connections before changing anything
List the applications and mail clients using the server, including their hostnames, ports and encryption modes. Assign someone to test each business workflow. Save the configuration and current queue status, and retain the previous valid certificate files. For shared agency and operations setups, agree who makes the change, who checks delivery and who can roll it back.
| Connection | Port | TLS policy | Acceptance check |
|---|---|---|---|
| Public incoming SMTP | 25 | Offer STARTTLS; accept delivery without TLS | External senders can deliver |
| Authenticated submission | 587 | Require STARTTLS before authentication | Applications authenticate and send |
| Implicit TLS submission | 465 | TLS from connection start | Client uses implicit TLS |
| IMAP mailbox access | 993 | TLS from connection start | Login works without certificate warnings |
Keep public SMTP compatible
For ordinary internet delivery, use opportunistic TLS. Postfix’s smtpd_ settings control incoming connections; smtp_ settings control outgoing delivery:
# /etc/postfix/main.cf — Postfix 3.4 or later
smtpd_tls_security_level = may
smtp_tls_security_level = may
smtpd_tls_chain_files = /etc/postfix/mail-tls.pemThe may policy permits unencrypted delivery and does not authenticate the destination. Requiring TLS globally on public port 25 can block legitimate incoming mail. Preserve any stronger, deliberately configured outbound policies for controlled destinations.
The combined PEM file contains the private key, its certificate, then intermediate certificates. Postfix recommends this interface to avoid separate-file replacement races. The deployment script below builds it.
Require encryption and authentication for sending
Put submission requirements in master.cf, separate from port 25. Adapt the existing service entry rather than creating a duplicate; retain your distribution’s appropriate service and chroot options.
# /etc/postfix/master.cf
submission inet n - y - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_auth_only=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_relay_restrictions=permit_sasl_authenticated,rejectThis assumes a working SASL authentication backend. Enabling AUTH does not connect Postfix to Dovecot automatically: check the backend and socket configuration against the Postfix SASL guide. Preserve necessary sender restrictions and filtering.
For port 465, use a separate service with smtpd_tls_wrappermode=yes, plus encryption, authentication and relay controls. Clients must select implicit TLS. Confirm that unauthenticated clients cannot send to external recipients through either submission service.
Match Dovecot settings to the installed version
Run dovecot --version first. These settings are for an existing Dovecot 2.4 configuration:
ssl = required
auth_allow_cleartext = no
ssl_server_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_server_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pemDovecot 2.3 uses different names and file syntax. Use documentation matching your installed version. The Dovecot TLS guide also confirms that a standard installation reads keys as root; giving the dovecot user access to the private key is unnecessary.
Configure clients explicitly for encrypted connections. A server can reject an insecure login, but cannot stop a misconfigured client from attempting to send a password first. Test any retained IMAP or POP STARTTLS ports too.
Make renewal include deployment
Replace mail.example.com with the hostname clients actually use. The certificate must cover that name. This issuance command requires an HTTP server serving the specified webroot and a publicly reachable challenge path on port 80:
sudo certbot certonly --webroot -w /var/www/html -d mail.example.comOtherwise, choose an appropriate automated authenticator, such as a DNS plugin. Confirm the actual lineage directory with sudo certbot certificates.
Save this root-owned script as /etc/letsencrypt/renewal-hooks/deploy/reload-mail, adjusting the lineage path. It skips unrelated certificate renewals and replaces Postfix’s combined file atomically:
#!/bin/sh
set -eu
umask 077
lineage=/etc/letsencrypt/live/mail.example.com
[ "${RENEWED_LINEAGE:-$lineage}" = "$lineage" ] || exit 0
tmp=$(mktemp /etc/postfix/mail-tls.pem.XXXXXX)
trap 'rm -f "$tmp"' EXIT
cat "$lineage/privkey.pem" "$lineage/fullchain.pem" > "$tmp"
mv "$tmp" /etc/postfix/mail-tls.pem
postfix check
doveconf -n > /dev/null
systemctl reload postfix
systemctl reload dovecotAfter issuance and configuration, run it once to create the combined file before reloading the new setup. Then test renewal:
sudo chmod 700 /etc/letsencrypt/renewal-hooks/deploy/reload-mail
sudo /etc/letsencrypt/renewal-hooks/deploy/reload-mail
sudo certbot renew --dry-run --run-deploy-hooksCertbot’s renewal documentation explains that this flag runs deploy hooks after a successful dry run, using the active certificate. It reloads live services. Check the renewal scheduler and route failures to someone responsible.
Test delivery as well as the certificate
Inspect configuration, queue status and logs:
sudo postfix check
sudo postconf -n
sudo doveconf -n
sudo postqueue -p
sudo journalctl -u postfix -u dovecot -fFrom outside the server’s network, test certificate trust and hostname identity:
openssl s_client -starttls smtp -connect mail.example.com:25 -servername mail.example.com -verify_hostname mail.example.com -verify_return_error
openssl s_client -starttls smtp -connect mail.example.com:587 -servername mail.example.com -verify_hostname mail.example.com -verify_return_error
openssl s_client -connect mail.example.com:465 -servername mail.example.com -verify_hostname mail.example.com -verify_return_error
openssl s_client -connect mail.example.com:993 -servername mail.example.com -verify_hostname mail.example.com -verify_return_error-servername sends SNI; -verify_hostname checks identity. -verify_return_error makes certificate verification failures abort the handshake, as documented in the OpenSSL test-client reference.
Finally, send external inbound and outbound messages, trigger an application notification, and check mailbox login and queue growth. A TLS handshake alone does not prove delivery. Monitor the certificate served externally; renewal on disk does not prove deployment.
Leave the team with tested client settings, renewal ownership, alerts and rollback instructions. If you need help reviewing the configuration or coordinating applications and suppliers, discuss your mail server with Greg.
Related on GrN.dk
- Sending Mail from a Linux Server with Postfix: A Reliable SMTP Relay Setup
- Sending Mail with Drupal: A Reliable Setup for Business-Critical Email
- Locked Out of Your Apple Developer Account? Fix Access Before October 1
Need help with this kind of work?
Discuss your mail server with Greg Get in touch with Greg.