Agent Wranglers

EML-76Recommended

Rotate DKIM keys every six months

Replace every DKIM key you manage at least every six months with a new selector. Revoke the old key once mail signed with it has been delivered.

How to do it

A key that lives for years has more time to leak or be cracked, and a routine makes an emergency change easy. M3AAWG's key rotation practice sets six months as the longest interval. Name selectors by date, such as s2026a. Publish the new public key, wait for its DNS time to live, then switch signing to it. Keep the old record for about 7 days, so messages still in queues and forwarders verify. Then publish the old selector with an empty p=, which RFC 6376 defines as a revoked key. Many sending services rotate their managed keys for you, so check their setting instead. Keep the private key in a secrets store, as Keep secrets in a secrets store says.

Examples

JavaScript example

const MAX_DKIM_KEY_AGE_DAYS = 183;

export function isDkimKeyDue(selector, now = new Date()) {
  const ageDays = (now - new Date(selector.createdAt)) / 86_400_000;
  return ageDays > MAX_DKIM_KEY_AGE_DAYS;
}

Python example

from datetime import datetime, UTC

MAX_DKIM_KEY_AGE_DAYS = 183

def is_dkim_key_due(selector, now: datetime | None = None) -> bool:
    now = now or datetime.now(UTC)
    return (now - selector.created_at).days > MAX_DKIM_KEY_AGE_DAYS

DNS example

s2026a._domainkey.example.com.  3600  IN  TXT  "v=DKIM1; k=rsa; p="

How to check

A scheduled job reads the selector in the last sent message's DKIM-Signature and fails when its key was created more than 183 days ago. dig +short TXT on a retired selector returns p= with no key.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/email/sending-domain-and-authentication/dkim-key-rotation">Agent Wranglers email playbook</a>. In code you write, add a comment next to it with the same link.