DKIM Explained: DomainKeys Identified Mail, RFC 6376, Selectors, Canonicalization, and Key Rotation

Everything a domain owner needs to publish, sign, validate, and rotate DKIM keys — from minimal RSA-2048 records to multi-selector zero-downtime rotation — with full RFC 6376 syntax, canonicalization explained, and worked deployment examples for Google Workspace, Microsoft 365, and SaaS senders.

This reference is provided in English. DKIM is specified in English-language RFCs and the canonical syntax (v=DKIM1, k=rsa, p=, c=relaxed/relaxed) does not translate; we keep the body in the source language so technical terms are consistent with the specifications.

TL;DR

  • DKIM (DomainKeys Identified Mail, RFC 6376) is a cryptographic email authentication mechanism: the sending server signs the message with a private key, the receiver verifies the signature against a public key published in DNS.
  • The signature lives in a DKIM-Signature: header. The public key lives in a DNS TXT record at <selector>._domainkey.<domain>.
  • Selectors let you publish multiple keys simultaneously (e.g. s1._domainkey, s2._domainkey), which is how zero-downtime key rotation works.
  • Canonicalization normalises headers and body before hashing. relaxed/relaxed is the production default — simple breaks on the slightest whitespace change in transit.
  • Use 2048-bit RSA keys (RFC 8301 recommends at least 2048 bits and retires SHA-1). Rotate every 3-6 months; immediately on suspected compromise.
  • DKIM survives forwarding (unlike SPF), which is why DMARC alignment on forwarded mail typically depends on DKIM. Forwarders that modify subject/body invalidate signatures — that is what ARC (RFC 8617) was designed to fix.

1. What is DKIM?

DKIM (DomainKeys Identified Mail) is a cryptographic email authentication standard defined in RFC 6376 that lets a domain owner take responsibility for a message by attaching a digital signature to it. The sending mail server hashes selected message headers and the body, signs the hash with a domain-controlled private key, and inserts the signature as a DKIM-Signature: header. Receiving mail servers fetch the corresponding public key from DNS and verify that the signature is valid — proving the message has not been altered in transit and originated from a server in possession of the domain's private key.

DKIM combined Yahoo's DomainKeys (RFC 4870, since obsoleted) with Cisco's Identified Internet Mail proposal; the merged standard was first published as RFC 4871 (2007) and updated by RFC 6376 (September 2011, the current standard). It is one of three complementary email-authentication primitives — alongside SPF (envelope-sender IP authorisation) and DMARC (policy + reporting) — that together harden SMTP against spoofing, phishing, and brand impersonation.

Critically, DKIM authenticates the message's integrity and binds it to a signing domain declared in the DKIM-Signature's d= tag — but that signing domain need not match the visible From: header the user sees. An attacker can sign their phishing mail under their own domain, pass DKIM on their domain, and still write any value they want in From:. That gap is exactly what DMARC closes by requiring identifier alignment between the DKIM d= domain and the From: header.

2. How DKIM works, step by step

  1. The domain owner generates an RSA key pair. The private key is loaded into the outbound mail server (Postfix, Exim, Microsoft 365, Google Workspace, Mailgun, etc.). The public key is published as a DNS TXT record at <selector>._domainkey.<domain>.
  2. When the outbound server sends a message, it selects which headers to sign (typically From, To, Subject, Date, Message-ID, MIME-Version, Content-Type) and applies canonicalization (see §6).
  3. It computes a hash (SHA-256 — SHA-1 is deprecated by RFC 8301) of the canonicalized headers and body, signs the hash with the private key, and inserts a DKIM-Signature: header containing the signing domain (d=), the selector (s=), the signed-headers list (h=), the canonicalization algorithms (c=), the body-hash (bh=), and the signature itself (b=).
  4. The receiving server parses the DKIM-Signature, extracts d= and s=, and queries DNS for <s>._domainkey.<d> to fetch the public key.
  5. The receiver re-canonicalizes the message using the same algorithms declared in c=, re-hashes the result, and verifies the signature cryptographically with the public key. If the signature is valid, the receiver records dkim=pass in the Authentication-Results: header — and the downstream DMARC evaluator checks whether the signing domain (d=) aligns with the From: header.

Possible DKIM result values reported in Authentication-Results::

  • pass — signature verified successfully.
  • fail — signature does not verify (key mismatch, body altered in transit, or canonicalization misapplied).
  • neutral — signature present but verification could not be completed (e.g. unrecognised canonicalization).
  • none — message had no DKIM-Signature header at all.
  • policy — signature was valid but rejected by local policy (e.g. key length below threshold).
  • temperror — transient DNS failure fetching the key; receiver SHOULD defer (4xx) and retry.
  • permerror — public-key record is malformed, revoked (p= empty), or missing.

3. DKIM DNS syntax

A DKIM public-key record is a DNS TXT record published at <selector>._domainkey.<domain>:

s1._domainkey.example.com.   IN   TXT   "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…"

Tag-by-tag anatomy of the public-key record:

v=DKIM1
Version tag. RECOMMENDED to appear first; receivers that find a missing or invalid v= reject the record. DKIM1 is the only defined version.
k=rsa
Key algorithm. rsa is universally supported. ed25519 (RFC 8463) is also defined but support is still uneven across receivers; dual-signing under both algorithms is the safe rollout path if ed25519 is a goal.
p=<base64-public-key>
The public key itself, base64-encoded. An empty p= means the key is revoked — receivers MUST reject signatures using a selector whose p= is empty (RFC 6376 §3.6.1). This is the safe way to retire a leaked key without breaking already-in-transit mail still referencing the selector.
t=<flags> (optional)
Comma-separated flag list. t=y declares the record is in test mode — receivers SHOULD NOT treat verification failures as policy violations. t=s forbids subdomain signing (the i= identity tag must exactly match d=).
s=<service-type> (optional)
Service-type restriction. s=email limits the key to email signing. Default * allows any DKIM-using service.
n=<notes> (optional)
Human-readable notes. Ignored by verifiers; intended for the DNS administrator.
h=<hash-algorithms> (optional)
Allowed hash algorithms. Defaults to all. Modern records should restrict to sha256 — RFC 8301 deprecates sha1.

The matching DKIM-Signature: header on the message side carries a different (overlapping) tag set including d= (signing domain), s= (selector), h= (signed-headers list), a= (signing algorithm e.g. rsa-sha256), c= (canonicalization), bh= (body hash), and b= (the signature). The combination of d= and s= is what tells the verifier which DNS record to fetch.

Records must be ASCII-safe; a 2048-bit RSA public key exceeds the DNS single-string 255-byte TXT limit and is automatically split into multiple double-quoted strings inside the same record. Resolvers concatenate them transparently before the verifier parses them.

4. DKIM selectors explained

A selector is a short string that, in combination with the signing domain, uniquely identifies a DKIM key. The selector lets a single domain publish multiple keys simultaneously — which is what makes zero-downtime key rotation possible. Selectors appear in the DKIM-Signature header's s= tag and become the leftmost label of the DNS query name:

DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=mail202604; …
       │                                              │
       │                                              └─→ selector
       └────────────────────────────────────────────→ signing domain (d=)

DNS lookup performed by the verifier:
       mail202604._domainkey.example.com    IN    TXT    "v=DKIM1; k=rsa; p=…"

Selector naming is a free-form choice but a few conventions matter:

Date-encoded selectors (recommended)
Use a date stamp like s202604, mail202604, or k2026q2 in the selector name. This makes key age visible in the DKIM-Signature header — anyone auditing your mail can see at a glance how old the signing key is.
Provider-prefixed selectors
SaaS senders use selectors like mailgun, k1, selector1, google, scph0119. When you on-board a SaaS sender, they publish their public key under <their-selector>._domainkey.<your-domain> — either via a CNAME alias to their key or as a delegated subdomain.
Selector reuse
NEVER reuse a selector name for a different key. Cached DNS responses across the receiver fleet will see signature failures on the boundary. Always use a fresh selector for each new key — date-encoded names make this trivial.

Multiple selectors can coexist indefinitely. Most well-tuned mail estates publish 2-3 active selectors at any time: the current signer, the previous signer (kept live while in-flight mail still references it), and an occasional "next" selector pre-published before a rotation switch-over.

5. DKIM canonicalization (simple vs relaxed)

Mail in transit gets touched: white-space gets folded, headers get refolded at SMTP-line boundaries, trailing empty lines come and go, a MTA might fix a missing Date: header. Canonicalization is the normalisation step DKIM applies before hashing so a benign whitespace change does not invalidate the signature. RFC 6376 §3.4 defines two canonicalization algorithms each for headers and body:

Algorithm Headers Body Robustness
simple Exact bytes; no normalisation at all. Exact bytes; only the final trailing CRLF sequence may be collapsed. Fragile. Any whitespace refolding by an in-path MTA invalidates the signature.
relaxed Header names lower-cased; runs of whitespace collapsed to single spaces; leading/trailing whitespace stripped; header-line folding normalised. Trailing empty lines removed; runs of whitespace within lines collapsed; lines ending in whitespace get the trailing whitespace stripped. Robust. Survives the typical MTA whitespace fixes that break simple.

The DKIM-Signature header declares both algorithms in the c= tag in the form c=<header-canon>/<body-canon>, for example c=relaxed/relaxed. Default if omitted: simple/simple — which is almost certainly the wrong default for any modern deployment.

Production guidance: use c=relaxed/relaxed in nearly every deployment. The handful of legitimate simple use cases (security-critical mail where any byte change must invalidate the signature, transaction notarisation, etc.) are well-understood niche cases. For ordinary notification, transactional, and marketing mail, relaxed/relaxed is the correct choice.

6. DKIM key rotation

DKIM keys age. A leaked private key lets an attacker forge messages under your domain with passing DKIM signatures; offline crypto analysis on harvested signatures slowly weakens older keys; staff turnover means historical key material drifts out of access control. The M3AAWG DKIM Key Rotation Best Common Practices recommend rotating production DKIM keys at least every 6 months, and immediately on any suspected compromise.

Zero-downtime rotation procedure:

  1. Generate a new RSA-2048 key pair and choose a fresh selector name. Date-encoded (s202610, k2026q4) makes the rotation point auditable.
  2. Publish the new public key at <new-selector>._domainkey.<domain> and wait for DNS propagation (typically 1-24 hours depending on your TTL).
  3. Switch the outbound mail server to sign with the new selector + new private key. The previous selector's DNS record stays live during this transition.
  4. Wait for in-flight mail to drain. Anything signed under the old selector before the switchover is still in transit and may be verified for up to ~7 days (worst case: greylisting, retries, forwarder queues).
  5. Revoke the old selector by setting its DNS record to v=DKIM1; p= (empty p=). This signals the key is retired without breaking older queues. After another propagation window, delete the record entirely.

On suspected compromise, compress the timeline: publish a new selector + switch signing infrastructure within the hour; revoke the old selector immediately (set p= empty); then audit your mail-server access logs back to the last key generation to scope the compromise window.

7. DKIM examples

7.1 Minimal RSA-2048 DKIM public-key record

s202604._domainkey.example.com.  IN  TXT  ( "v=DKIM1; k=rsa; "
                                              "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvDM…"
                                              "…rest of the base64-encoded key payload…" )

A typical published DKIM record. The p= value is split across multiple quoted strings inside one TXT record because a 2048-bit key exceeds the DNS single-string 255-byte limit; resolvers concatenate them automatically.

7.2 Revoked key (signals retirement)

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

An empty p= tells verifiers the key is retired. Used during rotation while in-flight mail still references the old selector, before the record is deleted entirely.

7.3 DKIM-Signature header on a signed message

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=example.com; s=s202604;
        h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type;
        bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=;
        b=Hyperv+wErx7…BASE64-SIGNATURE…+ZZ==

The verifier reads d=example.com and s=s202604, queries s202604._domainkey.example.com, fetches the public key, re-canonicalizes the headers in h= + the body under c=relaxed/relaxed, then verifies b= using rsa-sha256.

7.4 Google Workspace DKIM record (CNAME-delegated)

google._domainkey.example.com.  IN  TXT  "v=DKIM1; k=rsa; p=MIIBI…"

Google Workspace publishes its keys directly as TXT records under the customer's domain. The selector is typically google by default; multiple selectors are available for rotation. Generate the key in the Google Admin console; the console emits the exact TXT record content to paste into DNS.

7.5 Microsoft 365 DKIM record (CNAME-delegated)

selector1._domainkey.example.com.  IN  CNAME  selector1-example-com._domainkey.example.onmicrosoft.com.
selector2._domainkey.example.com.  IN  CNAME  selector2-example-com._domainkey.example.onmicrosoft.com.

Microsoft 365 publishes the actual key material under its own onmicrosoft.com namespace and delegates from the customer's domain via two CNAMEs (selector1 + selector2). Microsoft rotates between the two selectors on the customer's behalf — no DNS-side action required.

8. DKIM best practices

  • Use 2048-bit RSA keys. RFC 8301 recommends at least 2048 bits; do not introduce new 1024-bit keys in any deployment.
  • Sign with SHA-256. a=rsa-sha256. RFC 8301 deprecates SHA-1 unconditionally.
  • Use c=relaxed/relaxed canonicalization. The default simple/simple is fragile against in-path whitespace folding.
  • Sign the headers an attacker would forge. At minimum: From, To, Subject, Date, Message-ID, MIME-Version, Content-Type. Many SaaS senders also sign Reply-To and List-Unsubscribe.
  • Rotate selectors every 3-6 months following the M3AAWG guidance; immediately on any suspected key compromise.
  • Use date-encoded selectors. s202604 makes key age visible from the signature alone, no DNS lookup needed.
  • Publish 2-3 active selectors during rotation — old (drain), current (signing), and optionally a pre-published "next" selector.
  • Combine with SPF and DMARC. DKIM proves the message has not been altered, but it does not bind the signature to the From: header an end user sees — DMARC supplies that identifier alignment.
  • Keep the private key on the mail server only. Treat it like a TLS server certificate's private key: no copies in dev / staging / backup repositories, access scoped to the MTA service account, regenerated on staff offboarding when warranted.
  • Audit DKIM via DMARC aggregate reports. DMARC rua reports surface every d= domain that signed mail for your From: — the fast way to find unauthorized senders missing from your DKIM key inventory.

9. Common DKIM mistakes

  • Publishing a 1024-bit key in 2026. RFC 8301 keeps 1024 bits only as the minimum and recommends 2048. Generate 2048-bit; replace existing 1024-bit keys as a priority.
  • Reusing a selector for a new key. DNS caches the old TXT record across the receiver fleet; some receivers will see the new p=, others the cached old one — failure rate climbs to unacceptable levels for hours.
  • Splitting the public key across the wrong boundaries. A 2048-bit key MUST be split across multiple double-quoted strings INSIDE one TXT record; splitting across two TXT records breaks verification (only one record will be picked up).
  • Using c=simple/simple canonicalization. Almost any MTA in the path will refold whitespace and invalidate the signature. Use c=relaxed/relaxed.
  • Forgetting to sign Subject: in the h= list. An attacker can rewrite an unsigned subject line and the signature still validates against the original body.
  • Leaving t=y (test mode) set in production. Verifiers treat t=y signatures as advisory only — effectively disabling DMARC's DKIM alignment for that selector.
  • Deleting the old selector during rotation immediately. Mail signed under the old selector still in transit fails verification. Use the empty-p= revocation pattern first, wait a propagation window, then delete.
  • Storing the private key in version control. Even private repositories leak. The DKIM private key must live only on the signing MTA, with file permissions scoped to the MTA service account.

10. DKIM troubleshooting

dkim=none in Authentication-Results
No DKIM-Signature header on the message. Either the sending MTA is not configured to sign, or a SaaS sender on your domain has not been wired into the DKIM signing path. Audit which senders sign and which don't via DMARC aggregate reports.
dkim=fail — "body hash did not verify"
An in-path MTA modified the message body — content rewrite, footer injection, encoding change, etc. Most often a corporate gateway adding a disclaimer. Confirm by testing the same mail flow with the suspected gateway bypassed. If the rewrite is intentional, the gateway should re-sign under its own domain rather than passing through the original signature.
dkim=fail — "signature did not verify"
Header tampering OR the public key in DNS does not match the private key the MTA signed with. Confirm the DNS record matches the key the MTA loaded (paste the p= value into a DKIM validator). Confirm the canonicalization declared in c= matches what the signer applied.
dkim=permerror — "key not found"
No TXT record at <selector>._domainkey.<domain>. Either the selector is wrong, the DNS record was deleted, or DNS propagation has not completed yet. Verify with dig +short txt <selector>._domainkey.<domain>.
dkim=permerror — "key revoked"
The TXT record exists but p= is empty. The selector has been revoked — either intentionally during a rotation drain window, or an operator accidentally cleared the value. Confirm with the publishing party; if accidental, restore the p= value from the key backup.
dkim=temperror
DNS resolver timeout fetching the public key. Usually transient. Persistent failures point at authoritative-DNS reachability problems for the _domainkey sub-zone.
DKIM passes but DMARC still fails
DKIM alignment failure — the d= domain on the verified signature does not match the organisational domain of the From: header. Either sign with the From: domain, or in strict-DMARC deployments, ensure adkim=r permits subdomain alignment. See DMARC explained § alignment for the full alignment rules.

11. Frequently Asked Questions

What is DKIM?
DKIM (DomainKeys Identified Mail, RFC 6376) is a cryptographic email authentication mechanism. The sending mail server signs a hash of selected message headers and the message body with a private key; the receiver retrieves the corresponding public key from a DNS TXT record and verifies the signature. A valid signature proves the message has not been altered in transit and originated from a server in possession of the domain's private key.
What is a DKIM selector?
A selector is a short label that identifies which DKIM key was used to sign a message, allowing a domain to publish and rotate multiple keys simultaneously. The selector appears in the DKIM-Signature header as the s= tag (for example s=mailgun) and determines the DNS lookup name: receivers query <selector>._domainkey.<domain> to fetch the public key. Selectors should rotate every 3-6 months for security.
What does a DKIM DNS record look like?
A DKIM public-key record is a DNS TXT record at <selector>._domainkey.<domain> containing tag=value pairs separated by semicolons. A typical record is: s1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA…" — declaring the DKIM version, the key algorithm (RSA), and the base64-encoded public key.
What is DKIM canonicalization?
Canonicalization is the normalisation step applied to message headers and body before they are hashed. RFC 6376 §3.4 defines two algorithms each: simple (no normalisation — exact bytes) and relaxed (whitespace collapsed, header names lower-cased, trailing empty lines removed). The DKIM-Signature header's c= tag declares the chosen algorithms in the form c=<header>/<body>, for example c=relaxed/relaxed. Relaxed is the de-facto production default because most mail forwarders perform whitespace-folding that would otherwise invalidate simple signatures.
How often should I rotate DKIM keys?
Industry consensus and M3AAWG's "M3AAWG DKIM Key Rotation Best Common Practices" recommend rotating production DKIM keys at least every 6 months, and immediately on any suspected key compromise. Rotation is done by publishing a new selector with the new public key, switching the signing infrastructure to the new selector, then removing the old selector's DNS record once you have confirmed no in-transit mail still references it. Multiple selectors can be published simultaneously, which is how rotation stays zero-downtime.
Should I use 1024-bit or 2048-bit DKIM keys?
2048-bit RSA keys are the modern minimum. RFC 8301 (2018) requires signers to use RSA keys of at least 1024 bits and recommends at least 2048 bits, and requires verifiers to fail signatures using SHA-1 or RSA keys shorter than 1024 bits. Some legacy DNS providers limit a single TXT string to 255 bytes which makes a 2048-bit key span multiple quoted segments — resolvers concatenate them transparently. Use 2048-bit RSA in new deployments; do not introduce new 1024-bit keys.
Why does my DKIM signature fail after the email is forwarded?
Some forwarders alter the message — rewriting the Subject:, prepending an [EXTERNAL] tag, footer injection, or content-transfer-encoding changes — and any modification to a signed header or the signed body invalidates the cryptographic signature. The ARC (Authenticated Received Chain, RFC 8617) standard exists to preserve the authentication result across forwarding by adding cryptographic vouching headers as the message hops through trusted forwarders.

13. Audit your DKIM setup now

DMARC Analyzer's free Domain Security Checker performs live DKIM selector lookups, validates the public-key record syntax against RFC 6376, flags 1024-bit keys and the deprecated SHA-1 (RFC 8301), and surfaces revoked or missing selectors. Imported DMARC aggregate reports also show every d= signing domain that has signed mail for your From: header — the surest way to find unauthorised senders missing from your DKIM key inventory.

Check my DKIM record Sign up — Free plan