TLS certificate expired on sending server
The X.509 certificate presented by your SMTP server during `STARTTLS` is past its `notAfter` date, so receiving MTAs reject the handshake or fall back to cleartext.
Receivers that enforce DANE or MTA-STS (policy: enforce) will refuse delivery outright, bouncing mail with 454 4.7.0 TLS not available due to local problem or 421 4.7.0 TLS handshake failed. Peers without a strict policy downgrade to plaintext, which breaks TLS-RPT reporting, trips opportunistic-TLS alerts at Google and Microsoft, and exposes message contents in transit. Expect a sharp drop in inbox placement and a flood of tls=TLS_error entries in receiver logs within hours of expiry.
What causes it
- ACME renewal cron (
certbot renew,acme.sh --cron) failed silently — usually a port 80 HTTP-01 challenge blocked by a firewall rule or a reverse proxy that stopped forwarding/.well-known/acme-challenge/. - Certificate was issued manually by an ops engineer who left, with no renewal automation and no monitoring on
notAfter. - Postfix or Exim is pointing at a stale
smtpd_tls_cert_filepath after a renewal wrote the new cert elsewhere, and the daemon was never reloaded. - DNS CAA record was tightened to a different CA, so the ACME client now fails the
caacheck during renewal but keeps serving the old cert until expiry. - Wildcard cert renewed on the web host but never copied to the mail server — common when
mail.example.comandwww.example.comshare a cert distributed by rsync or Ansible that silently broke.
How to fix it
Confirm the expiry and which cert is actually being served
Hit port 25 with openssl s_client and read the notAfter field. Do this against the public hostname your MX points to, not localhost — a split DNS or load balancer may be presenting a different cert than the one on disk.
echo | openssl s_client -starttls smtp -connect mail.example.com:25 -servername mail.example.com 2>/dev/null | openssl x509 -noout -subject -issuer -dates Force an immediate Let's Encrypt renewal
Run certbot with --force-renewal to bypass the 30-day threshold, then verify the new cert chain. If HTTP-01 is blocked, switch to DNS-01 — most providers (Cloudflare, Route 53, deSEC) have a certbot plugin. For mail servers behind NAT, DNS-01 is the only reliable long-term option.
sudo certbot renew --force-renewal --cert-name mail.example.com
sudo certbot certificates # confirm new notAfter Reload the MTA so it picks up the new cert
Certbot's --deploy-hook is the right place for this, but if you renewed manually, reload Postfix, Exim, or Haraka explicitly. A restart is not required and will drop active connections — reload re-reads the cert files in place.
sudo systemctl reload postfix
# or for exim: sudo systemctl reload exim4
# verify:
sudo postconf -n | grep smtpd_tls_cert_file Add expiry monitoring so this never bounces mail again
Set a check that alerts at 14 days before notAfter. A Prometheus blackbox_exporter with the tls_connect module, an Uptime Kuma TLS monitor, or a weekly cron that pipes openssl s_client into date -d all work. Pair it with a TLS-RPT record (_smtp._tls.example.com TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com") so receivers tell you when handshakes fail.
_smtp._tls.example.com. 3600 IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com" Fixed it? Run a fresh test to confirm.
Test my inbox →