DKIM key rotation: why nobody does it (and why you should)
DKIM signs every outbound message with an asymmetric key. The public half lives in DNS at
selector._domainkey.example.com; the private half lives in your mail server.
Industry guidance (Google, Microsoft, NIST) recommends rotating every 6 months. The
modal age in our scan database: 4-7 years. Some are pre-2018.
Why rotate
Crypto keys age in three ways:
- Algorithmic deprecation. Pre-2018 keys are usually 1024-bit RSA. NIST classified RSA-1024 as "legacy" since 2013 and as "disallowed" since 2030 is the projected deadline. RFC 8301 mandates 2048+ for DKIM.
- Server compromise. If your mail server has been touched by an attacker over its lifetime — even briefly — the private key may have been exfiltrated. You don't always notice. Rotation is the only reliable mitigation.
- Cryptographic forward secrecy. Long-lived keys mean the same key signs years of historical mail. A future leak retroactively allows attackers to forge "from-the-past" messages.
Why nobody rotates
Because the rotation procedure is annoying and the consequences of getting it wrong are "all your mail goes to spam". Specifically:
- You can't replace a key in-place — receivers cache the old public key for the TTL window.
- Mail signed with the old key keeps arriving at recipients for hours/days after rotation. If you remove the old DNS record too soon, those messages fail DKIM.
- Mailing list re-distribution (forwards, archives) can re-inject old-signed messages weeks later.
The protocol designers anticipated this with selectors.
The dual-selector rotation pattern
A DKIM signature in a message header references its selector by name:
DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=2024a; ...
^^^^^
selector
Receivers fetch 2024a._domainkey.example.com for that specific message's
verification. Multiple selectors can coexist. So:
- Day 0. Generate new keypair. Publish public key as
2026b._domainkey.example.com(a new selector). Old key stays as2024a._domainkey.example.com. - Day 7. Configure mail server to sign new outbound mail with selector
2026b. Both records live in DNS; receivers verify whichever signature each message references. - Day 60. Old in-flight mail has cleared. Remove the old
2024aDNS record. Done.
Total downtime: zero. Mail signed with the old key continues to verify until day 60; mail signed with the new key verifies from day 7 onwards. The window in between is the only "both records live" period — harmless.
Generating the keypair
$ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out dkim-2026b.private.pem
$ openssl pkey -in dkim-2026b.private.pem -pubout -outform DER 2>/dev/null \
| base64 -w0
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA....
The base64 string is your p= value. The DNS record:
2026b._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...."
Most DNS providers reject TXT records longer than 255 chars. Split into multiple quoted strings:
"v=DKIM1; k=rsa; " "p=MIIBIjANBg... " "AQEFAAOCAQ8A...."
The DNS server concatenates them on read. Cosmetically ugly, semantically equivalent.
For SaaS-vendor DKIM (SendGrid, Mailgun, etc.)
You don't manage the private key — the vendor does. Rotation procedure varies but is usually one click in their dashboard. Re-publish their new CNAME or TXT record. Same dual-selector window applies.
How UnveilScan flags this
Our dkim checker (Extended profile) probes 41 known selectors and parses
the public key for:
- Modulus < 1024 bits (HIGH — broken by default browsers).
- Modulus < 2048 bits (MEDIUM — RFC 8301 violation).
- Empty
p=(revoked but not removed — LOW). - Key signed with SHA-1 (MEDIUM).
We don't currently flag "this key looks old" because age can't be determined from DNS alone. But if your scan reports modulus < 2048, that's a 2018-era keypair you should rotate today.
Audit your DKIM keys now
Extended scan probes 41 selectors and reports modulus size + signing algorithm.
See pricing