Bali, Indonesia
Insights

Moving to Shorter Certificate Lifetimes? Check DANE TLSA Records Before Mail Defers

October 30, 2026
0:00
Your mail server publishes DANE TLSA records, and you have just moved certificate renewal to an automated ACME client that renews more often. Everything looks fine after the next renewal. The certificate is valid, webmail loads, and your own test emails arrive. Some senders, though, stop delivering and leave your mail sitting in their queues. A common cause is that the renewal generated a new private key, and the hash published in DNS no longer matches what your server presents during STARTTLS. This guide walks through checking that match directly from the command line, before and after a renewal, and how to keep it from breaking as renewals become more frequent.
DANE (DNS-Based Authentication of Named Entities) lets a domain publish, in DNSSEC-signed DNS, what certificate or key its mail server is supposed to present. For SMTP the record lives under the MX host name, not the bare domain. If your MX is mail.example.com, the record is at _25._tcp.mail.example.com. Every MX host needs its own record. A TLSA record has three numbers followed by a hash. The most common combination for mail is 3 1 1:
  • 3 (DANE-EE) means "match the server's own certificate," with no CA chain check.
  • 1 (selector) means "look at the public key (SubjectPublicKeyInfo), not the whole certificate."
  • 1 (matching type) means "the data is a SHA-256 hash."
The important detail is the selector. A 3 1 1 record pins the public key, not the certificate. You can renew a certificate as many times as you like and the record keeps matching, as long as the key pair stays the same. The moment the renewal tool creates a fresh key, the hash changes and the record is wrong. Senders that validate DANE, such as Postfix configured with smtp_tls_security_level = dane, treat a mismatch as a failed secure connection. They do not fall back to plaintext, because that would defeat the point of DANE. The mail is deferred and retried, and if the mismatch lasts long enough it eventually bounces, depending on the sender's queue settings. Senders that do not validate DANE never look at the record and deliver normally. That split is why this problem often reaches support as "some people can email us, some can't," which looks like a reputation or blocklist issue at first glance. TLSA records are only used when the zone is DNSSEC-signed and validates. If DNSSEC itself is broken, you have a different problem. For that side of it, see Thinking DNSSEC Re-Signs Itself After Moving DNS to BIND, Until RRSIGs Expire. The timing matters more now than it used to. According to CA/Browser Forum rules, the maximum certificate lifetime is 200 days from March 15, 2026, dropping to 100 days from March 15, 2027, and to 47 days by 2029. If each renewal rotates the key, every renewal is a chance to break DANE. Doing renewals by hand at that pace is not realistic either, which is covered in Why Manual SSL Renewal Tracking Fails as Certificate Lifetimes Shrink to 47 Days.
Start with what DNS says. Use a validating resolver, and check the ad (authenticated data) flag in the response header. Without it, DANE-aware senders will ignore the record anyway.
BASH
# Find the MX hosts for the domain
dig +short MX example.com

# Read the TLSA record for one MX host (repeat for each MX)
dig +short TLSA _25._tcp.mail.example.com

# Check that the answer is DNSSEC-validated: look for 'ad' in the flags line
dig +dnssec TLSA _25._tcp.mail.example.com | grep -E 'flags:|TLSA'
The +short answer gives you the usage, selector, matching type, and the hash. Some dig versions split long hex data with spaces, so remove spaces before comparing, and compare case-insensitively since dig typically prints uppercase hex and openssl prints lowercase. If the ad flag is missing, check whether the resolver you queried actually validates DNSSEC before concluding the zone is broken. Querying a known validating resolver directly with dig @resolver-ip helps separate the two.
Next, connect to port 25 the way a sending server would, pull the certificate from the STARTTLS handshake, extract the public key, and hash it in the same format as a 3 1 1 record. Run this from a host that can reach port 25 outbound. Many residential networks and some cloud providers block outbound port 25, which makes the connection hang rather than fail cleanly.
BASH
# Hash the live public key (SPKI, SHA-256) as a 3 1 1 record would
openssl s_client -connect mail.example.com:25 -starttls smtp \
  -servername mail.example.com </dev/null 2>/dev/null \
  | openssl x509 -noout -pubkey \
  | openssl pkey -pubin -outform DER \
  | openssl dgst -sha256

# Sample output format (label text varies by OpenSSL version):
# SHA2-256(stdin)= 3f9a...e1c4
The hex string after the = is what should appear in your TLSA record. If it matches, DANE senders are happy with the current key. If it doesn't match any published 3 1 1 record, they are deferring right now. OpenSSL 1.1.0 and later can also do the comparison for you. Adding -dane_tlsa_domain mail.example.com and -dane_tlsa_rrdata '3 1 1 <hash>' to the s_client command makes it report whether the TLSA data matched the presented certificate in its verification output. Check openssl s_client -help on your build to confirm the options are available. If you run Postfix, its posttls-finger tool can test a destination with DANE as well, which is closer to how a real sender behaves. One more thing worth checking when there are several MX hosts: they do not always share the same certificate or key. A backup MX that was renewed separately can quietly drift out of sync with its own TLSA record.
The first two steps tell you whether things are broken now. The more useful check is whether the next renewal will break them. That means looking at how your ACME client handles keys and hashing the key on disk before the server reloads it. With Certbot, each certificate has a renewal config file. If key reuse is enabled for that certificate, the file contains reuse_key = True. Certbot's long-standing default has been to generate a new key on renewal unless told otherwise, so confirm the behavior for your installed version. acme.sh has its own key handling and options, so check its documentation for the version you run.
BASH
# Is key reuse enabled for this certificate? (Certbot)
grep -i 'reuse_key' /etc/letsencrypt/renewal/mail.example.com.conf

# Hash the private key on disk the same way as the live check
sudo openssl pkey -in /etc/letsencrypt/live/mail.example.com/privkey.pem \
  -pubout -outform DER | openssl dgst -sha256
The second command reads the private key, so it needs root and should not be pasted into tickets or shared logs. Only the resulting hash is safe to share. If the on-disk hash matches the TLSA record and key reuse is on, the next renewal will keep the same key. If the on-disk hash differs from what the server presents, a new key is already waiting and will break DANE as soon as the mail server reloads. The paths above are Certbot's defaults. Mail servers often read certificates from a copied location, so confirm which file Exim, Postfix, or Dovecot actually load before trusting the result.
There are two practical ways to live with frequent renewals. The simpler one is to keep the key stable. Turn on key reuse in the ACME client for the mail certificate, and the 3 1 1 record stays valid across renewals. The trade-off is that you are no longer rotating the key automatically, so you need to plan a deliberate rotation from time to time, especially if the key could have been exposed. The other way is to roll the key with a two-record overlap. DANE allows more than one TLSA record at the same name, and a sender accepts the connection if any one of them matches. The sequence looks like this:
  1. Generate the next key in advance, without deploying it.
  2. Publish a second 3 1 1 record with the next key's hash, alongside the current one.
  3. Wait at least the TLSA record's TTL, plus some margin, so resolvers that cached the old answer have picked up both records.
  4. Deploy the certificate that uses the new key and reload the mail server. Rerun the Step 2 check to confirm the live hash matches the new record.
  5. After another TTL has passed, remove the old record.
Skipping the wait in step 3 is where rollovers usually go wrong. A sender whose resolver still caches the single old record will see a mismatch even though DNS now looks correct when you query it. Some admins switch to a 2 1 1 record instead, which pins the issuing CA's key rather than their own. That avoids rolling TLSA on every key change, but it ties you to that CA's intermediate key. If the CA changes intermediates, the record breaks for a reason outside your control. It is a reasonable option only if you track the CA's intermediate changes closely. Whichever approach you choose, treat the Step 2 hash check as part of every renewal, not something you run after senders start complaining. Put it in the renewal hook or in monitoring, compare it against every TLSA record for every MX host, and alert on a mismatch. With certificate lifetimes getting shorter, the renewal itself is routine. What keeps mail flowing is making sure the key DNS promises and the key the server presents are still the same one.