The moment DKIM breaks, nobody says “interesting.” They say “why are invoices going to spam,” “why did password resets vanish,” and “why does the CEO’s email look like phishing.” DKIM key rotation is one of those jobs where nothing visible should happen—except it absolutely will if you get sloppy.
This is a production-grade runbook for rotating DKIM keys with calm, measurable steps. You’ll dual-sign, stage DNS correctly, verify with commands that don’t lie, and cut over when evidence says it’s safe. If you like drama, take up theater. If you run mail systems, keep a rollback plan and a spare selector.
What DKIM rotation actually is (and what it isn’t)
DKIM rotation is the act of changing the cryptographic key that signs your outgoing mail. In practice, that means:
- You generate a new private key on the signer (MTA or outbound relay).
- You publish the corresponding public key in DNS under a selector.
- You switch signing to use the new selector (or sign with both during transition).
- You keep the old public key available long enough for verifiers to validate older messages.
What it is not: a deliverability “tuning” exercise. Rotation doesn’t make you more trustworthy on its own; it reduces risk from key compromise and operational drift. If your mail is already failing SPF/DMARC alignment, rotating DKIM won’t save you. It may, however, expose that you were living on borrowed time.
Why rotation causes drama
Three reasons:
- DNS is a distributed cache system with opinions. You don’t “change DNS,” you negotiate with resolvers you don’t control.
- Email is asynchronous. Messages can be delayed, retried, queued, or delivered hours later, still needing the old key for validation.
- People confuse domains. The visible From domain, the DKIM d= domain, and the SMTP envelope domain are related but not the same. Confusing them turns “simple” changes into multi-team incident calls.
Opinionated guidance up front: rotate with dual-signing if you can. If you can’t, you still rotate safely, but you’ll be more careful with timing and retention of old keys in DNS. Also: never rotate during a major launch. Your future self will send you a postcard from the spam folder.
Interesting facts and a little history
- DKIM came from a merger. DomainKeys (Yahoo) and Identified Internet Mail (Cisco) were combined into DKIM, standardized as RFC 4871 in 2007.
- DKIM doesn’t encrypt email. It signs selected headers and the body (or part of it) to detect tampering, not to keep secrets.
- The selector is a versioning primitive. DKIM was built with rotation in mind: selectors exist so you can publish multiple keys simultaneously.
- Early DKIM deployments were RSA-only. RSA became the default; Ed25519 later appeared as an option in newer specs and implementations, but adoption is uneven.
- 2048-bit keys became the “serious” default. 1024-bit RSA keys are still seen, but some receivers treat them as weak or policy-violating.
- DKIM validation happens at receipt time. That means receivers need DNS access to your public key when they evaluate the message—not when you sent it.
- DKIM can survive forwarding better than SPF. SPF checks the path; DKIM checks the content. Forwarders break SPF routinely; DKIM often survives if the forwarder doesn’t rewrite the signed parts.
- DMARC made DKIM operationally mandatory. Once DMARC enforcement became common, DKIM stopped being “nice to have” and became “don’t page me.”
The mental model: selectors, keys, DNS, and time
Think of DKIM as four moving parts:
- Signer: the system that holds the private key and adds the DKIM-Signature header (Postfix + OpenDKIM, a cloud relay, or an ESP).
- Selector: a string like
s2026q1that chooses which key to fetch in DNS. - DNS record: a TXT record at
<selector>._domainkey.<domain>holding the public key and metadata. - Receiver: Gmail, Outlook, and everyone else doing DNS lookups and signature validation when they accept the message.
Time is the hidden dependency
The system has two separate clocks:
- DNS propagation and caching: TTL plus resolver behavior.
- Mail delivery latency: queues, retries, graylisting, congestion, and “that one legacy appliance” that tries again tomorrow.
Rotation fails when you remove the old key from DNS before the world is done validating mail signed with it. It also fails when you switch signers before the new key is visible to receivers. The answer is boring: overlap.
One quote, because it fits
Hope is not a strategy.
— attributed to various engineering leaders; commonly used in operations and reliability circles.
Joke 1: DNS caching is like glitter: you think you cleaned it up, and then it shows up in your car three weeks later.
Preflight: inventory and blast-radius control
Before you touch keys, answer three questions with evidence:
- Who is signing today? Maybe it’s your MTAs. Maybe it’s your ESP. Maybe it’s both (marketing vs transactional). “Both” is common and not inherently bad—until you rotate one and forget the other.
- What domains and subdomains are in play?
example.com,mail.example.com,news.example.com, and custom return-path domains can all exist. Each might have separate selectors and policies. - What policy depends on DKIM passing? DMARC enforcement (quarantine/reject) turns a small DKIM mistake into a full stop.
Choose a selector naming scheme that doesn’t age poorly
Selectors are strings. That’s both power and chaos. Pick something that stays sane across years and teams:
- Good:
s2026q1,mta1-2026-01,rotate-01 - Bad:
default,dkim,test,new(because “new” becomes “old” before your change ticket closes)
Decide on overlap duration
My practical recommendation:
- Keep the old selector published for at least 7 days after cutover for most orgs.
- Keep it 30 days if you have long mail queues, regulated systems, or any “we batch-send weekly statements” behavior.
Receivers can validate old messages later (think: delayed delivery, reprocessing, or mailbox moves). There’s no prize for removing old DNS keys quickly. The prize is not getting paged.
Practical tasks with commands, outputs, and decisions
The point of commands is not busywork. It’s to turn “I think” into “I know.” These tasks are written for a typical Linux-based environment with Postfix + OpenDKIM, plus generic DNS verification. Adjust paths and service names if you’re using another signer, but keep the discipline: observe, change, observe again.
Task 1: Confirm what selector is currently signing
Send yourself a message from your system, then inspect headers in your mailbox. On a Linux mail server you can also look for DKIM-Signature in logs if you log milter results.
cr0x@server:~$ sudo grep -R "DKIM-Signature" -n /var/log/mail.log | tail -n 3
Jan 04 09:12:11 mta1 postfix/cleanup[23111]: 4A2B9123: message-id=<...>
Jan 04 09:12:11 mta1 opendkim[1122]: 4A2B9123: DKIM-Signature field added (s=selector2025, d=example.com)
Jan 04 09:12:12 mta1 postfix/qmgr[977]: 4A2B9123: from=<noreply@example.com>, size=..., nrcpt=1 (queue active)
What it means: You are currently signing with selector selector2025 for d=example.com.
Decision: This is your “old” selector. You must keep its DNS record during and after rotation.
Task 2: Enumerate all DKIM DNS records you currently publish
cr0x@server:~$ dig +short TXT selector2025._domainkey.example.com
"v=DKIM1; k=rsa; p=MIIBIjANBgkq...IDAQAB"
What it means: That selector exists and publishes a public key.
Decision: If dig returns nothing, stop. You’re signing with a selector that isn’t published, and rotation is not your biggest problem.
Task 3: Check effective TTL and whether you can safely lower it
cr0x@server:~$ dig TXT selector2025._domainkey.example.com +noall +answer
selector2025._domainkey.example.com. 3600 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkq...IDAQAB"
What it means: TTL is 3600 seconds (1 hour).
Decision: If TTL is huge (like 86400), lower it a day before the cutover so caches drain faster. If you can’t change TTL (managed DNS with constraints), plan a longer overlap and do dual-signing if possible.
Task 4: Generate a new DKIM keypair (OpenDKIM example)
cr0x@server:~$ sudo mkdir -p /etc/opendkim/keys/example.com/selector2026
cr0x@server:~$ sudo opendkim-genkey -b 2048 -D /etc/opendkim/keys/example.com/selector2026 -d example.com -s selector2026
cr0x@server:~$ sudo ls -l /etc/opendkim/keys/example.com/selector2026
total 8
-rw------- 1 root root 1704 Jan 4 10:02 selector2026.private
-rw-r--r-- 1 root root 451 Jan 4 10:02 selector2026.txt
What it means: You have a private key and a TXT template for DNS.
Decision: Use 2048-bit RSA unless you have a strong reason not to. If your platform supports Ed25519 and your receivers accept it, you can evaluate it—but don’t run a compatibility science experiment during a rotation.
Task 5: Validate key file permissions (private keys are not group projects)
cr0x@server:~$ sudo stat -c "%n %a %U:%G" /etc/opendkim/keys/example.com/selector2026/selector2026.private
/etc/opendkim/keys/example.com/selector2026/selector2026.private 600 root:root
What it means: File is readable only by root.
Decision: Ensure the OpenDKIM user can read it (often by ownership or group). Mis-permissions cause silent “signing stopped” outages.
Task 6: Configure OpenDKIM to know the new key (KeyTable/SigningTable)
cr0x@server:~$ sudo grep -n "example.com" /etc/opendkim/KeyTable /etc/opendkim/SigningTable
/etc/opendkim/KeyTable:12:selector2025._domainkey.example.com example.com:selector2025:/etc/opendkim/keys/example.com/selector2025/selector2025.private
/etc/opendkim/SigningTable:9:*@example.com selector2025._domainkey.example.com
What it means: Everything points to selector2025.
Decision: Add the new selector lines. If you plan dual-signing, your approach depends on your software (some support multiple signatures; others don’t). If you can’t dual-sign, you’ll do a cutover but keep old DNS published.
Task 7: Add the new selector to KeyTable
cr0x@server:~$ sudo bash -lc 'echo "selector2026._domainkey.example.com example.com:selector2026:/etc/opendkim/keys/example.com/selector2026/selector2026.private" >> /etc/opendkim/KeyTable'
cr0x@server:~$ sudo tail -n 2 /etc/opendkim/KeyTable
selector2025._domainkey.example.com example.com:selector2025:/etc/opendkim/keys/example.com/selector2025/selector2025.private
selector2026._domainkey.example.com example.com:selector2026:/etc/opendkim/keys/example.com/selector2026/selector2026.private
What it means: OpenDKIM now knows where the new private key lives.
Decision: If you are using a database-backed KeyTable or a different signer, equivalent step applies: register the selector and key path.
Task 8: Switch signing table to the new selector (single-signing cutover example)
cr0x@server:~$ sudo sed -i 's/\*@example.com selector2025\._domainkey\.example\.com/*@example.com selector2026._domainkey.example.com/' /etc/opendkim/SigningTable
cr0x@server:~$ sudo grep -n "\*@example.com" /etc/opendkim/SigningTable
9:*@example.com selector2026._domainkey.example.com
What it means: New mail will be signed with selector2026 once OpenDKIM reloads.
Decision: Do not reload yet if DNS isn’t published. Signing with a selector nobody can fetch equals DKIM=fail at receivers.
Task 9: Extract the DNS TXT value you must publish
cr0x@server:~$ sudo cat /etc/opendkim/keys/example.com/selector2026/selector2026.txt
selector2026._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp....IDAQAB" ) ; ----- DKIM key selector2026 for example.com
What it means: That p= value is what receivers will use.
Decision: Publish it exactly. No extra quotes from your DNS UI, no line breaks inserted into the key, no missing semicolons. DNS tooling varies; validate after publishing.
Task 10: Publish the new DKIM record, then verify from multiple resolvers
cr0x@server:~$ dig +noall +answer TXT selector2026._domainkey.example.com
selector2026._domainkey.example.com. 300 IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp....IDAQAB"
What it means: The record exists and TTL is 300 seconds (5 minutes).
Decision: If TTL is not what you intended, fix it now while nobody depends on it. Also query a known public resolver to reduce “my corporate DNS is lying to me” risk.
cr0x@server:~$ dig @1.1.1.1 +short TXT selector2026._domainkey.example.com
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp....IDAQAB"
What it means: A public resolver sees it.
Decision: Don’t cut over until at least two independent resolvers return the new key consistently.
Task 11: Reload OpenDKIM cleanly and confirm it didn’t error
cr0x@server:~$ sudo systemctl reload opendkim
cr0x@server:~$ sudo systemctl status opendkim --no-pager -l
● opendkim.service - OpenDKIM Milter
Loaded: loaded (/lib/systemd/system/opendkim.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2026-01-04 09:00:03 UTC; 1h 8min ago
Docs: man:opendkim(8)
Main PID: 1122 (opendkim)
Status: "Running"
What it means: Service is up. That’s necessary, not sufficient.
Decision: Immediately check logs for key loading errors; OpenDKIM can run while failing to sign.
Task 12: Confirm OpenDKIM is using the new selector in logs
cr0x@server:~$ sudo tail -n 20 /var/log/mail.log | grep -E "opendkim|DKIM-Signature" | tail -n 5
Jan 04 10:12:07 mta1 opendkim[1122]: 6C9FD123: DKIM-Signature field added (s=selector2026, d=example.com)
Jan 04 10:12:07 mta1 postfix/qmgr[977]: 6C9FD123: from=<noreply@example.com>, size=..., nrcpt=1 (queue active)
What it means: Mail is now being signed with selector2026.
Decision: Proceed to external verification (Gmail headers or a test mailbox) before declaring victory.
Task 13: Verify DKIM passes on a received message (header inspection)
In Gmail or Outlook, view original message source. You’re looking for authentication results.
cr0x@server:~$ python3 - <<'PY'
import re,sys
msg=open('/tmp/raw.eml','r',errors='ignore').read()
m=re.search(r'Authentication-Results:.*', msg, re.I)
print(m.group(0) if m else "no Authentication-Results header found")
PY
Authentication-Results: mx.google.com; dkim=pass header.i=@example.com header.s=selector2026 header.b=AbCdEf...
What it means: DKIM is passing and the selector is correct.
Decision: If DKIM=fail, stop and debug before moving forward with decommissioning the old key.
Task 14: Track ongoing use of old selector (to know when it’s safe to retire)
cr0x@server:~$ sudo grep -R "s=selector2025" -n /var/log/mail.log | tail -n 5
Jan 03 23:48:51 mta1 opendkim[1122]: 1F0A9123: DKIM-Signature field added (s=selector2025, d=example.com)
What it means: The last observed mail signed with the old selector was yesterday.
Decision: If this still appears after cutover, you have another signer, a second MTA, or a partial deployment. Don’t delete old DNS until you know all signers are switched.
Task 15: Confirm DMARC alignment won’t be harmed by the rotation
cr0x@server:~$ dig +short TXT _dmarc.example.com
"v=DMARC1; p=quarantine; rua=mailto:dmarc-agg@example.com; adkim=s; aspf=s"
What it means: DMARC is strict alignment (adkim=s). That means d= in DKIM must match the From domain exactly.
Decision: Ensure your signer uses d=example.com (not a subdomain) if From is @example.com. Rotation is a great time to accidentally change d= and cause DMARC failures.
Task 16: Detect broken DNS formatting (quotes, semicolons, and split strings)
cr0x@server:~$ dig +short TXT selector2026._domainkey.example.com | tr -d '"' | grep -E "v=DKIM1;|p="
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp....IDAQAB
What it means: You can see v=DKIM1 and p= cleanly in the returned TXT.
Decision: If your output contains stray parentheses, broken fragments, or missing p=, fix DNS. Some consoles wrap long TXT records incorrectly if you paste with whitespace.
Joke 2: Rotating DKIM keys without monitoring is like swapping parachutes mid-air because the label looked old.
Checklists / step-by-step plan (zero-drama rotation)
Plan A: Best practice (dual-signing selectors)
If your signing stack supports adding two DKIM-Signature headers (old and new selectors), do it. It buys you the right kind of laziness: receivers can validate with either key while caches and stragglers catch up.
- Pick a new selector with a sane naming scheme (e.g.,
s2026q1). - Lower TTL on the current DKIM record(s) 24 hours ahead of time (e.g., to 300 seconds), if your DNS change process allows it.
- Generate a new keypair on the signer, store private key securely, set permissions, and register it in signer config.
- Publish the new public key in DNS under the new selector. Verify via multiple resolvers.
- Enable dual-signing: sign each message with both selectors for at least 48 hours (often longer in large orgs).
- Measure: confirm receivers report DKIM=pass with the new selector consistently.
- Stop signing with the old selector once you’re confident, but keep the old selector’s DNS record.
- Retire the old DNS key only after your overlap period and after you have evidence no systems are still using it.
Plan B: Single-signing cutover (still safe, just less forgiving)
- Pick selector and generate keys.
- Publish new selector in DNS first. Verify from outside your network.
- Wait at least one TTL window (and realistically more) for caches to pick it up.
- Switch signing to the new selector and reload signer.
- Verify DKIM pass using real mailbox headers (Gmail/Outlook) and your logs.
- Keep old selector DNS published for the overlap period.
Rollback plan (write it before you need it)
Rollbacks should be boring. If you’re improvising, you’re already losing time.
- Rollback trigger: DKIM fail rate spikes; DMARC failures appear; key lookups return NXDOMAIN intermittently; major receivers show “bad signature.”
- Rollback action: switch signing table back to the old selector and reload signer; keep both DNS records published.
- Rollback verification: confirm logs show old selector signing; confirm DKIM pass in external mailbox.
Important: rollback is only possible if you didn’t delete the old key record (and you kept the old private key accessible to the signer). You’d be surprised how often people “clean up” early.
Change window rules (my hard opinions)
- Do it mid-week during staffed hours. Friday rotations are a hobby, not a practice.
- Don’t couple it with other changes. Key rotation plus outbound routing changes is how you get into “multiple plausible causes” hell.
- Announce to stakeholders who own sender streams. Marketing platforms, CRM, support ticket systems, and internal apps. You’re rotating their reputation machinery; they deserve a heads-up.
Fast diagnosis playbook
When deliverability drops after a rotation, you need a fast, ordered path. Not a brainstorming session.
First: Determine whether DKIM is failing because of DNS or signing
- Check one real received message (Gmail/Outlook headers): look for
Authentication-Resultsand whether it saysdkim=passordkim=fail, plus whichheader.sselector it used. - If it’s failing, query DNS for that selector from a public resolver and from your server. If DNS returns nothing or inconsistent answers, you have a propagation/caching issue.
- If DNS looks fine, inspect signer logs for “key not found,” “permission denied,” or “no signature added.” That’s your signing pipeline.
Second: Check DMARC alignment impact
- Confirm the DKIM
d=value matches the visible From domain, especially if DMARC has strict alignment (adkim=s). - Confirm no new outbound path is rewriting the From domain or adding a different DKIM signature that confuses receivers.
Third: Identify partial cutover and multi-signer confusion
- Search logs for both selectors. If both still appear days later, you have more than one signer.
- Check marketing ESPs or cloud relays that sign on your behalf. They may have their own DKIM configuration and selectors.
- Look for messages with multiple DKIM-Signature headers and see which ones pass/fail. A failing signature can still be okay if another passes, but DMARC alignment rules matter.
The bottleneck you’re hunting
Most “DKIM rotation incidents” are either:
- DNS record missing or malformed for the new selector.
- Signer misconfigured (still signing old selector, wrong domain, wrong key path, wrong permissions).
- Unaccounted signer (one business unit’s system never got the memo).
Common mistakes: symptom → root cause → fix
1) Symptom: DKIM suddenly fails for all mail after cutover
Root cause: You switched signing to the new selector before publishing the new DNS record (or before caches could see it).
Fix: Publish the record, verify via public resolvers, then either wait out TTL or rollback signing to old selector until DNS is visible.
2) Symptom: DKIM passes sometimes, fails sometimes
Root cause: Split-brain DNS (multiple authoritative answers during propagation), or some receivers are hitting cached NXDOMAIN.
Fix: Ensure DNS provider shows a single consistent record; confirm all authoritative nameservers serve the same content; extend overlap; avoid deleting old key too soon.
3) Symptom: DKIM header is missing entirely
Root cause: Milter not running, Postfix not connected to it, or OpenDKIM cannot read the private key due to permissions/SELinux.
Fix: Check service status and logs; validate Postfix smtpd_milters; correct key ownership and SELinux contexts where applicable.
4) Symptom: DKIM shows “bad signature” even though DNS is correct
Root cause: Something modifies the message after signing (footer injection, line wrapping, content filters), or canonicalization mismatch.
Fix: Ensure DKIM signing happens as late as possible in the pipeline; avoid post-signing content modification; re-check canonicalization settings.
5) Symptom: DKIM passes but DMARC fails
Root cause: DKIM d= domain isn’t aligned with the From domain (especially with strict alignment).
Fix: Sign with the From domain, or adjust DMARC alignment policy knowingly. Don’t “fix” it by weakening DMARC unless you accept the security tradeoff.
6) Symptom: Some senders still use the old selector weeks later
Root cause: A second outbound system (ESP, SaaS, regional MTA) wasn’t updated.
Fix: Inventory all outbound sources; search DMARC aggregate reports (if you have them) and logs; update each signer; keep old key in DNS until the last one is migrated.
7) Symptom: Receivers report “key too short” or treat mail as suspicious
Root cause: You generated a 1024-bit RSA key (or a receiver has policy against it).
Fix: Move to 2048-bit RSA; re-publish; cut over again. If you’re rotating anyway, don’t ship a weak key because it’s faster.
8) Symptom: DNS TXT record appears truncated
Root cause: Copy/paste or DNS UI wrapped and inserted whitespace or lost fragments; some providers require quoting conventions.
Fix: Re-enter record using the provider’s correct multi-string format; validate the returned p= is contiguous when retrieved.
Three corporate mini-stories from the trenches
Mini-story 1: The incident caused by a wrong assumption
They rotated DKIM on a Thursday morning. The change ticket was tidy: new key, new selector, update signer. The engineer did the obvious verification: dig from their laptop showed the new TXT record. They cut over signing. Everything looked fine for five minutes.
Then support started forwarding screenshots: “Your message was blocked.” Transactional email to a large consumer mailbox provider began landing in spam or failing DMARC. The on-call saw that DKIM was failing at that provider, but passing in a smaller test inbox. Confusing. The kind of confusing that wastes an hour.
The wrong assumption was simple: “If my resolver can see it, everyone can.” Their corporate DNS was configured to forward queries to a fast resolver that had already picked up the new record. The major mailbox provider, however, was hitting a different cache path and occasionally seeing NXDOMAIN for the new selector. It wasn’t “slow propagation” in the mystical sense; it was normal distributed caching behavior amplified by a TTL that had been 24 hours until the day before.
The fix wasn’t heroic. They rolled back signing to the old selector, left the new selector published, waited a full day, then cut over again. The lesson that stuck: verification must include public resolvers and authoritative checks, not just “whatever DNS my laptop happens to use today.”
Mini-story 2: The optimization that backfired
A different company wanted “clean DNS.” Their security team pushed for aggressive removal of old DKIM keys: rotate weekly, delete immediately after cutover, keep the zone minimal. It sounded crisp in a slide deck.
It backfired in a boring way. Their outbound mail included some systems that queued messages for hours (batch sends, delayed notifications, retries during provider throttling). A subset of messages were signed with the old key and delivered late, after the DNS record for the old selector had been removed. Receivers couldn’t validate them. Some providers treated that as a stronger negative signal than an unsigned message because it looked like tampering.
They didn’t have a “DKIM is failing because you deleted the key too early” alarm. They had a “deliverability is down” dashboard, which is the operational equivalent of a smoke alarm that triggers after the kitchen is already on fire.
They reversed course: keep old selectors in DNS for weeks, not days. They also introduced selector versioning by quarter and limited rotation frequency to something aligned with actual risk. Cleaner DNS did not improve deliverability. It improved nobody’s life.
Mini-story 3: The boring but correct practice that saved the day
One org had a habit that looked excessive until it wasn’t: they maintained a “mail auth inventory” file listing every system that sends mail, which domain it uses in From, which DKIM selector it signs with, and who owns it. It was not glamorous. It was updated by humans. It was correct.
When they planned a DKIM rotation for the parent domain, they used that inventory to stage the change across systems: two on-prem MTAs, one cloud relay, and a SaaS ticketing tool that signed on their behalf with a delegated subdomain. They rotated each stream deliberately and kept old keys published for a month.
Halfway through, they discovered one regional MTA still signing with an older selector. Not because anyone was incompetent—because the region had a different maintenance window and a separate config management pipeline. The inventory made that visible. They didn’t delete the old selector. No incident happened. Nobody noticed. That’s the goal.
They also had a pre-written rollback snippet in their config management system: one change to revert signing selector and redeploy. They never used it. The fact that they could was why the rotation stayed calm.
FAQ
1) How often should we rotate DKIM keys?
Rotate on a schedule that matches your risk: commonly quarterly to annually. Rotate immediately if you suspect key compromise, a signer was exposed, or you lost control of the private key.
2) Can I reuse the same selector and just change the key in DNS?
You can, but you shouldn’t. Selectors exist so you can overlap keys and avoid cache chaos. Reusing a selector forces a hard cutover and makes troubleshooting harder because “selector name” no longer implies “which key version.”
3) How long do I keep the old DKIM public key in DNS?
At least 7 days after you stop signing with it; 30 days is safer in enterprises. If you have long queue times or periodic batch sends, keep it longer. Removing it early doesn’t buy much and can hurt late-delivered mail.
4) What TTL should DKIM TXT records use?
Common values are 300 to 3600 seconds. For rotation, lowering TTL a day in advance helps. After rotation, you can raise it modestly if you want fewer DNS queries, but don’t chase micro-optimizations.
5) What key size should we use?
Use 2048-bit RSA unless your environment has a validated alternative and receiver compatibility is confirmed. 1024-bit keys are increasingly treated as weak or unacceptable by policy.
6) If DKIM passes, do we still need SPF?
Yes. SPF and DKIM fail in different ways. DMARC lets either (aligned) DKIM or SPF satisfy policy. Keeping both gives you resilience across forwarding, relays, and weird sender paths.
7) Why does DKIM fail only for forwarded messages?
Forwarders sometimes modify the body or headers (adding footers, rewriting subject tags, altering MIME boundaries). If they touch signed parts, the signature breaks. Solutions include minimizing modifications after signing and using DMARC-friendly forwarding mechanisms when possible.
8) Can we rotate without downtime if we use a third-party ESP?
Usually yes, but your controls are different: you generate/publish DNS keys and configure the ESP’s selector usage. The same overlap rule applies: publish new selector first, verify, then switch. Keep old selector published after.
9) What’s the safest way to test before flipping production traffic?
Use a dedicated subdomain or a small subset of mail streams if your signer supports per-sender or per-domain policies. Publish the new selector, sign test mail with it, and validate in multiple major inbox providers.
10) Do multiple DKIM signatures confuse receivers?
No, multiple signatures are common. Receivers can validate any/all of them. What matters is that at least one aligned DKIM signature passes for DMARC (depending on policy and alignment mode).
Conclusion: next steps you can do this week
If you want DKIM rotation to be a non-event, treat it like any other production change: stage it, verify it externally, overlap it longer than your instincts want, and don’t delete things early.
- Write down your sender inventory: every system, every From domain, every DKIM selector.
- Pick a selector scheme that survives org churn (quarter-based or year-based is fine).
- Do a dry run in a non-critical subdomain to validate your DNS tooling and signer reload behavior.
- Add two monitors: (1) “DKIM signature present” on outbound samples, (2) “DKIM pass rate” via received mailbox headers or available telemetry.
- Schedule rotation with overlap: publish new key, verify on public resolvers, then cut over signing, keep old key published for weeks.
Your goal is not to prove you can rotate keys. Your goal is that nobody notices you did.