2026年11月14日
2026年11月14日
Let’s Encrypt Auto-Renewal for Mail Servers (Postfix and Dovecot)
This article is a localized edition of the Japanese original. Read the Japanese original
For a mail server (Postfix and Dovecot), you can obtain and renew Let's Encrypt SSL/TLS certificates with certbot, just as for a web server. However, certbot has no feature that rewrites Postfix or Dovecot configuration automatically, so the division of labor is: certbot obtains and renews the certificate, the mail software is configured with the file locations, and it is reloaded after each renewal.
The commands in this article use Ubuntu 24.04 as the example. certbot's behavior was checked against the official certbot documentation as of November 2026, and the certificate lifetimes against Let's Encrypt's official announcements.
Prerequisites
- The A record (and the AAAA record if you use IPv6) for the mail server's host name (for example,
mail.example.com) points to this server - If you use HTTP validation to obtain the certificate, port 80 on this server is reachable from the internet
- Postfix and Dovecot are installed
Step 1: Install certbot
sudo apt update
sudo apt install certbot
The official certbot site recommends installing it with snap. Either way, the commands you use are the same.
Step 2: Obtain the certificate
Choose the method for a mail server depending on whether a web server is running on it.
| Server situation | Method |
|---|---|
| No web server is running | --standalone (certbot temporarily listens on port 80) |
| A web server is running on the same server | --webroot (places a validation file in the web server's document root) |
| Port 80 cannot be opened | DNS validation (requires a plugin for your DNS provider) |
# When no web server is running
sudo certbot certonly --standalone -d mail.example.com
# When a web server runs on the same server (document root is /var/www/html in this example)
sudo certbot certonly --webroot -w /var/www/html -d mail.example.com
The first time you run it, certbot asks for a contact email address and for agreement to the terms of service. Once the certificate is issued, the following files are created.
| File | Contents |
|---|---|
/etc/letsencrypt/live/mail.example.com/fullchain.pem |
Server certificate plus intermediate certificate |
/etc/letsencrypt/live/mail.example.com/privkey.pem |
Private key |
The files under live are switched to point to the new certificate on every renewal. Do not copy them; put these paths in your configuration as they are.
With --standalone, certbot also listens on port 80 at renewal time. Note that closing port 80 in the firewall makes renewal fail.
Step 3: Configure the certificate in Postfix
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 check
sudo systemctl reload postfix
postconf -e rewrites the corresponding lines in /etc/postfix/main.cf. smtpd_tls_security_level = may encrypts with STARTTLS when the other side supports it (a mail server receiving on port 25 uses may so that it can still receive mail from senders without TLS). Authenticated sending on port 587 (submission) is configured on the submission line in /etc/postfix/master.cf.
Step 4: Configure the certificate in Dovecot
The setting names differ between Dovecot 2.3 and 2.4. Check your version with dovecot --version. Ubuntu 24.04 ships Dovecot 2.3, and Debian 13 ships Dovecot 2.4.
Dovecot 2.3 (/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
The < means "read the contents of this file"; it does not work without it.
Dovecot 2.4 (on Debian 13, the same /etc/dovecot/conf.d/10-ssl.conf already has lines with default values, so edit those lines)
ssl = required
ssl_server_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_server_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem
Check the configuration and apply it.
sudo doveconf -n | grep -i ssl
sudo systemctl reload dovecot
Dovecot reads the certificate and private key with root privileges, so you do not need to loosen the private key's permissions.
Step 5: Reload Postfix and Dovecot after renewal
Even after certbot renews the certificate, Postfix and Dovecot may keep using the old one until they are reloaded. Use a certbot deploy hook to reload them only when a renewal succeeds.
Executable files placed in /etc/letsencrypt/renewal-hooks/deploy/ run every time a certificate is successfully obtained or renewed.
sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh
#!/bin/sh
systemctl reload postfix
systemctl reload dovecot
sudo chmod 755 /etc/letsencrypt/renewal-hooks/deploy/reload-mail.sh
If the same server has other certificates and you want the hook to run only when the mail certificate is renewed, test the RENEWED_LINEAGE environment variable that certbot passes (the live directory of the renewed certificate).
#!/bin/sh
case "$RENEWED_LINEAGE" in
*/mail.example.com)
systemctl reload postfix
systemctl reload dovecot
;;
esac
Step 6: Confirm that automatic renewal is running
certbot installed with apt or snap sets up a timer that runs certbot renew periodically. certbot renew renews only certificates that are close to expiry. You normally do not need to add certbot renew to cron yourself.
# Check for the renewal timer (certbot.timer with apt, snap.certbot.renew.timer with snap)
systemctl list-timers | grep -i certbot
# List the certificates you have and their expiry dates
sudo certbot certificates
# Rehearse a renewal (the real certificates do not change)
sudo certbot renew --dry-run
Deploy hooks do not run with --dry-run. To test including the hooks, add --run-deploy-hooks (this actually reloads Postfix and Dovecot).
sudo certbot renew --dry-run --run-deploy-hooks
Renewals are logged in /var/log/letsencrypt/letsencrypt.log. If a renewal fails, look at this log first.
Step 7: Confirm the mail software uses the new certificate
Connect to each port with openssl s_client and print the certificate's name and expiry date.
# IMAPS (port 993)
openssl s_client -connect mail.example.com:993 -servername mail.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -enddate
# SMTP submission (port 587, STARTTLS)
openssl s_client -connect mail.example.com:587 -starttls smtp -servername mail.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -enddate
# SMTP (port 25, STARTTLS)
openssl s_client -connect mail.example.com:25 -starttls smtp -servername mail.example.com </dev/null 2>/dev/null \
| openssl x509 -noout -subject -enddate
If the notAfter= date matches the expiry date shown by sudo certbot certificates, the new certificate is in use. If it still shows the old date, the reload did not happen.
Notes on certificate lifetimes and expiry notices
- As of November 2026, a standard Let's Encrypt certificate is valid for 90 days. Let's Encrypt has announced that it will shorten lifetimes in stages: 64 days from February 10, 2027, and 45 days from February 16, 2028. Keep renewal automatic and do not rely on homemade schemes that renew every fixed number of days.
- Let's Encrypt stopped sending expiry reminder emails on June 4, 2025. Set up your own expiry monitoring, for example by checking the remaining days with the
opensslcommands above or by checking certificate expiry with a monitoring tool.
For automatic renewal on the web server side, see How to automatically renew Let's Encrypt SSL certificates, and for mail encryption settings, see Setting up STARTTLS on a mail server.
Summary
- Obtain a certificate for the mail server's host name with
certbot certonly(--standaloneor--webroot). - Set the
livepaths in Postfix (smtpd_tls_cert_fileandsmtpd_tls_key_file) and in Dovecot (ssl_certandssl_keyfor 2.3,ssl_server_cert_fileandssl_server_key_filefor 2.4). - Put a hook in
/etc/letsencrypt/renewal-hooks/deploy/so that Postfix and Dovecot are reloaded on every renewal. - Confirm automatic renewal with
systemctl list-timersandcertbot renew --dry-run, and check the expiry of the certificate actually in use withopenssl s_client.
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)