Enable TLS on a Linux Mail Server Without Breaking Delivery

Illustrated infographic summarizing: Enable TLS on a Linux Mail Server Without Breaking Delivery

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
Enable only the services you need, and test every exposed endpoint.

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.pem

The 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,reject

This 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.pem

Dovecot 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.com

Otherwise, 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 dovecot

After 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-hooks

Certbot’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 -f

From 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

Need help with this kind of work?

Discuss your mail server with Greg Get in touch with Greg.

Sources

Latest articles

Make monthly reporting easier to repeat with AI for Excel, Python and consistent checks. Get imports, error lists and reconciliation under control so the numbers can be verified.

A supplier PDF can influence more than an AI summary. Follow its path to a CRM update and see where validation, tool permissions and destination controls matter.

Check whether AI shopping channels show the right product, variant, price and availability, then trace discrepancies from your catalog through to checkout.

Add approved hours from Clockify to draft invoices in Dinero. AI writes service descriptions, while fixed rules govern amounts, approvals and reruns.

A blanket AI restriction can limit search discovery. Compare Google and Bing controls, agree content permissions, and check what your CMS actually delivers.

Measure AI automation costs per accepted result, including retries and human review. Check caching, batch processing and spending controls before scaling.

A 502 after maintenance can interrupt enquiries or checkout. Trace the NGINX-to-PHP connection, diagnose the failure, and check the fix survives a restart.

Let AI customer service retrieve order status from Shopify and Shipmondo. Learn how to define the scope, verify the customer's identity and hand over cases when information is uncertain.

Move a useful AI workflow into company-controlled projects, with clear ownership, tested permissions, service accounts and a practical plan for replacing credentials.

Drupal 10 reaches end of life on 9 December 2026. Decide whether to upgrade first or combine it with a relaunch, with clear budgets, compatibility checks and launch criteria.