DKIM Best Practices: The Synthesis Operator-Discipline Reference (15 Prescriptive Rules for a Healthy DKIM Deployment — Algorithm + Key Size + Selector Naming + Rotation Cadence + Canonicalization + Header List + AUID + l= Prohibition + t=y Burn-In + Multi-Signature + Monitoring + DNS Publication + Revocation + Documentation + Quarterly Audit)
The cluster-closing 13th DKIM-cluster spoke. Where the protocol primer (help_dkim_explained.php) covers WHAT DKIM is and the 12 sibling deep-dive pages cover one tag or topic each, this page covers HOW to deploy and operate DKIM correctly — the 15 prescriptive rules synthesized from RFC 6376, RFC 8301, RFC 8463, RFC 8617, and a decade of operator experience that distinguish a healthy DKIM posture from a fragile one. Algorithm (2048-bit RSA floor + ed25519 dual-publish), selector naming (descriptive + dated), rotation cadence (annual + 7-day overlap), canonicalization (relaxed/relaxed), header list (oversigned From/Subject/Date), AUID (empty default), l= prohibition (replay-attack vector), t=y discipline (burn-in then REMOVE), multi-signature (single default), monitoring (three surfaces), DNS publication (multi-string chunking + verification), emergency revocation (empty-p= within minutes), documentation (per-selector change log), and quarterly cluster audit (verify every rule against every production selector). Each rule cross-references the deep-dive page that documents the underlying mechanism in detail.
This reference is provided in English. The DKIM tag vocabulary (v=DKIM1, k=rsa, k=ed25519, p=, h=sha256, t=y, t=s, s=email, c=relaxed/relaxed, i=, l=) and the RFC terminology (RFC 6376 §5.4 From mandate, RFC 8301 §3 2048-bit minimum, RFC 8463 ed25519, RFC 8617 ARC, RFC 7489 §3.1.1 "any aligns wins") are protocol identifiers that do not translate. We keep the body in the source language so technical terms remain consistent with IETF RFC documentation.
TL;DR — the 15 DKIM best-practice rules
A healthy DKIM deployment in 2026 follows 15 prescriptive rules synthesized from RFC 6376, RFC 8301, RFC 8463, RFC 8617, and a decade of operator experience across the major mail ecosystems.
- 2048-bit RSA minimum. RFC 8301 §3. 1024-bit is broken. (§2, algorithm)
- Dual-publish k=rsa + k=ed25519 on separate selectors for forward compatibility. (§2)
- Descriptive dated selector names.
E.g.,
sel-2026a._domainkey— notk1ordefault. (§3, selectors) - Annual rotation with 7-day dual-selector overlap, 30-day in-flight drain, 30-day empty-p= retention. (§4, rotation)
- c=relaxed/relaxed canonicalization. Tolerates intermediary whitespace edits. (§5, canonicalization)
- Sign From, Subject, Date, To, Reply-To, MIME-Version, Content-Type at minimum; OVERSIGN From, Subject, Date with the empty-double-list trick. (§6, h= list)
- Leave i= empty (defaults to d=) unless documented per-AUID delegation required. (§7, AUID)
- NEVER use l= body-length tag — replay-attack vector. (§8, l=)
- t=y for 24-72h burn-in, then REMOVE. Stale t=y silently disables DMARC-via-DKIM. (§9, t=)
- Single signature default; multi-signature only for documented algorithm-migration or sub-brand isolation. (§10, multi-signature)
- Monitor Authentication-Results + DMARC aggregate daily; alert on verdict-distribution shifts. (§11, monitoring)
- Multi-string TXT chunking for 2048-bit RSA keys per RFC 1035 §3.3.14. (§12, DNS)
- Emergency revocation = empty-p= within minutes of compromise detection; NEVER delete the record. (§13, revocation)
- Document every selector with name, deployment date, rotation history, owner. (§14, documentation)
- Quarterly cluster audit: verify every above rule against every production selector. (§15, checklist)
Each rule below has its own deep-dive subsection explaining the rule, the rationale, the operator action, and the cross-references to the sibling cluster page that documents the underlying mechanism in detail.
1. What makes a DKIM deployment "best practice"
DKIM (RFC 6376) is a cryptographic protocol that works correctly at the protocol level for many different configurations — but only a subset of those configurations are operationally robust against the threat models that mature operators actually face: forwarder body-modification attacks, replay attacks (RFC 6376 §8), key compromise, intermediary header injection, sub- brand spoofing, DMARC alignment failures, and the long-running ed25519 vs RSA algorithm migration.
A "best practice" deployment is the configuration that survives those threat models without operational drift. The 15 rules synthesized below are the cluster-wide consensus from the 12 sibling DKIM-cluster pages — each rule traces back to a specific RFC mandate or a documented failure mode that operators have observed repeatedly.
Where this page fits in the cluster:
- Protocol pillar — what DKIM does (the cryptography, the verification flow, the verdict codes).
- Key-record syntax — how to encode the published public key (RFC 6376 §3.6.2).
- Header tag anatomy — what the signer emits per message (RFC 6376 §3.5).
- The 8 focused deep-dive pages: canonicalization, selectors, cryptography, key rotation, replay attacks, failures explained, alignment with DMARC, and troubleshooting.
- The 2 provider deployment guides: Microsoft 365, Google Workspace.
- THIS page is the synthesis layer — the actionable ruleset that operators execute against once they understand the underlying mechanism.
How to use this page: read the 15 TL;DR rules above, then jump to the rule subsection corresponding to whichever rule you are currently uncertain about. Each subsection cross-references the deep-dive page that documents the underlying mechanism — read both if you want the full background.
2. Algorithm and key size: 2048-bit RSA floor, dual-publish ed25519
Rule 1: 2048-bit RSA minimum.
Per RFC 8301 §3, "Signers MUST NOT sign with rsa
keys shorter than 1024 bits, and SHOULD use keys
of 2048 bits or larger". The 1024-bit floor is a
legacy compromise from RFC 6376 (2011); modern
receivers downgrade verdicts on 1024-bit signatures
to dkim=policy or treat them as
dkim=fail. No production deployment
in 2026 should publish a 1024-bit RSA key.
Rule 2: dual-publish k=rsa + k=ed25519
on separate selectors. RFC 8463 added
k=ed25519 as a second valid key type
with structural advantages (32-byte public keys,
64-byte signatures, faster verification). Receiver
coverage of ed25519 has grown steadily since 2018
and is now near-universal among major receivers in
2026, but legacy spam appliances and small ISPs
still produce dkim=neutral or
dkim=permerror on ed25519. The
dual-publish posture gives the signer a fallback:
; Selector 1 — RSA-2048:
selector1._domainkey.example.com IN TXT ( "v=DKIM1; k=rsa; "
"p=MIIBIjANBgkqhkiG9w0BAQEF..." )
; Selector 2 — ed25519:
selector2._domainkey.example.com IN TXT "v=DKIM1; k=ed25519; p=11qYAYKxCrfVS/7TyWQHOg7hcvPapiMlrwIaaPcHURo="
The signer adds both signatures or alternates per message. For DMARC alignment, RFC 7489 §3.1.1 "any aligns wins" — if the receiver understands either signature and finds it aligned, DMARC passes via DKIM.
Cross-reference: help_dkim_cryptography_basics.php documents the RSA vs ed25519 algorithm choice in depth, including the multi-year migration timeline.
3. Selector naming: descriptive and dated
Rule 3: use descriptive dated
selector names like sel-2026a,
sel-2026b, m365-selector1
— not default, k1,
dkim, or mail.
The selector name is operator-chosen and has no
protocol semantics — receivers concatenate it
with _domainkey.<d-value> and
query as-is. But the name carries operational
meaning for the humans maintaining the zone:
- Dated selectors
(
sel-2026a) make rotation history visible in the zone file — when you seesel-2024a,sel-2025a, andsel-2026ain the zone, you know rotation has been happening on schedule. Generic names (k1,k2) carry no rotation signal. - Source-named selectors
(
m365-selector1,sendgrid-s1,internal-postfix-2026) make selector ownership visible — when an outage occurs and you need to identify which signer is responsible for a particular d= signature, the selector name itself points to the team. - Avoid
default— many provider wizards still suggest this name; it conflicts when multiple signers try to claim it and produces operationally- opaque diagnostics.
Cross-reference: help_dkim_selectors_explained.php documents the selector vocabulary in depth.
4. Rotation cadence: annual with dual-selector overlap
Rule 4: rotate every signing key once per year using the dual-selector overlap discipline.
The 67-day end-to-end rotation lifecycle:
- Day 0: generate a new
keypair, publish the public key at a NEW
selector (e.g.,
sel-2026bif currently signing withsel-2026a). The old selector continues signing. - Day 7: verify the new
selector resolves from multiple geographic
resolvers
(
dig +short sel-2026b._domainkey.example.com TXT @8.8.8.8,@1.1.1.1,@9.9.9.9). Switch the signer to use the new selector. - Days 7-37: the old selector is still published in DNS but no new mail signs with it. In-flight messages (forwarded, queued, archived) may still reference the old selector during verification.
- Day 37: publish empty-p=
at the old selector. Any straggler
verifications now fail with
dkim=permerror(the canonical "permanently revoked" signal). - Day 67: delete the empty-p= record entirely.
Emergency rotation (key compromise detected) skips the 7-day overlap: publish empty-p= at the affected selector IMMEDIATELY (within minutes of detection), stand up a new selector with a fresh keypair, switch the signer. The 30-day retention timeline remains.
Cross-reference: help_dkim_key_rotation.php documents the rotation playbook with timing diagrams.
5. Canonicalization: c=relaxed/relaxed default
Rule 5: use
c=relaxed/relaxed. The format is
c=<header-canon>/<body-canon>;
both halves should be relaxed.
The four canonicalization combinations and their operational survival rates:
c=simple/simple— intolerant of any modification. Any whitespace change anywhere in the body produces body-hash mismatch. Survival rate through real-world mail-flow: low. AVOID.c=simple/relaxed— rare; the header is more sensitive than the body, opposite of normal threat modeling. AVOID.c=relaxed/simple— also rare; the body is intolerant which is the wrong way around. AVOID.c=relaxed/relaxed— the modern default. Tolerates trailing whitespace, blank-line collapse, line- ending normalization. USE THIS.
The relaxed body canonicalization tolerates intermediary body modifications that are inherent in real mail flow: forwarders adding trailing spaces, mailing lists adding List-Unsubscribe footers, content-scanning gateways normalizing encoding. ARC sealing (RFC 8617) is the structural fix for cases where even relaxed canonicalization is not enough.
Cross-reference: help_dkim_canonicalization.php documents the byte-level canonicalization algorithms with worked examples.
6. Header list: sign what matters, oversign what attackers spoof
Rule 6: the
h= tag in the DKIM-Signature header
declares which message headers are covered by
the signature. The minimum operator-discipline
list:
h=From:Subject:Date:To:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding:Sender;
The From mandate: RFC 6376 §5.4
mandates that From: be signed. A DKIM signature
without From in h= is non-compliant; modern
receivers reject the signature as
dkim=permerror.
The oversigning trick: append a second copy of From, Subject, and Date at the end of h=:
h=From:Subject:Date:To:Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding:Sender:From:Subject:Date;
The duplicate-name trick tells the verifier "if a SECOND From header appears in the message, include it in the signature calculation". This neutralizes the attack where a forwarder adds a forged second From: above the signed one — a naive verifier reads the first From: (the forged one) but the signature only protects the second From: (the original). With oversigning, the verifier MUST find the signed From: at EVERY position and the attack collapses.
Cross-reference: help_dkim_signatures_explained.php documents the h= tag and the oversigning technique in the byte-by-byte tag anatomy.
7. AUID (i= tag): leave empty by default
Rule 7: leave the
i= tag empty in the DKIM-Signature
header — receivers will default it to
@<d-value> per RFC 6376 §3.5.
The AUID (Agent or User Identifier) is intended for fine-grained signing-authority delegation — e.g., a shared signer that signs different sub-brands with different AUIDs. In practice the feature is rarely used because:
- Selector-level isolation (a separate selector
per sub-brand) is structurally cleaner — each
sub-brand publishes its own key, owns its own
rotation, and the receiver sees the
attribution naturally via
s=andd=. - AUID-level isolation requires the publisher
to publish a
t=sflag in the key record and to maintain a per-AUID allowlist — more moving parts, more drift risk. - DMARC alignment is computed on
d=, not oni=, so AUID isolation does not affect alignment.
When to use i= explicitly: only
when you have a documented per-AUID delegation
requirement that cannot be satisfied by
selector-level isolation. In every other case,
omit i= entirely.
8. NEVER use the l= body-length tag
Rule 8: do not deploy l=.
The l= tag declares that only the
first N body bytes are covered by the signature;
everything after byte N is unsigned. A replay
attacker can:
- Capture a legitimate signed message from your domain.
- Append arbitrary content (phishing CTAs, malware links, drive-by JavaScript) to the body AFTER byte N.
- Replay the modified message — the signature still verifies because the appended content is outside the signed range.
RFC 6376 §3.5 itself cautions against
l=: "Use of the 'l=' tag might
allow display of fraudulent content without
appropriate warning to end users". Modern
signing libraries do not emit l= by
default. If you find l= in your
DKIM-Signature output, audit the signer
configuration and remove it immediately.
Cross-reference: help_dkim_replay_attacks.php documents the full l= threat model with concrete attack scenarios.
9. The t=y testing flag: 24-72h burn-in, then REMOVE
Rule 9: use t=y in
the KEY RECORD for the first 24 to 72 hours
after deploying a new selector, then REMOVE the
flag.
The t=y flag tells verifiers "this
selector is in deployment-test mode" — verifiers
compute the verdict and surface it in
Authentication-Results headers (so you can
inspect it) but do NOT feed the verdict into
DMARC alignment or spam-filter input. This is
intentional during burn-in: you can debug the
cryptography without affecting deliverability.
The problem: t=y left in production
SILENTLY DISABLES DKIM-based DMARC alignment
forever. Every receiver downgrades the resulting
dkim=pass to "pass but ignore"; the
cryptography is valid but DMARC does not credit
it. This is one of the top three causes of
"DKIM is configured but DMARC still fails"
tickets.
Operator discipline:
- Set a calendar reminder for 72 hours after
every new selector deployment specifically
to remove
t=y. - Run a quarterly cluster audit (Rule 15) that
verifies no production selector carries
t=y. - The Domain Security Checker tool flags
production selectors with stale
t=y.
Cross-reference: help_dkim_dns_syntax.php documents the t= flag in the key-record syntax deep dive.
10. Multi-signature: single default, multiple for documented use cases
Rule 10: sign with ONE DKIM-Signature header by default. Add additional signatures only for two documented use cases:
- Algorithm migration: during the multi-year k=rsa to k=ed25519 transition, dual-publish both keys at separate selectors and let the signer add BOTH signatures so receivers that have not implemented RFC 8463 fall back to the RSA signature.
- Sub-brand isolation: when a shared signer handles multiple sub-brands with different selectors — but this is usually better handled via per-tenant signing-configuration rather than multi-signature on a single message.
For DMARC alignment, RFC 7489
§3.1.1 states "any aligns wins" — if ANY of the
dkim=pass results has a d= aligned
with the From: header, DMARC alignment is
satisfied. So multi-signature can improve
DMARC robustness against single-signature
failures.
Anti-pattern: spraying signatures "just in case". Every additional signature adds: DNS publication overhead (one selector per signature), monitoring overhead (one verdict per signature to track), and rotation overhead (each selector rotates independently). Default to ONE signature; add more deliberately.
Cross-reference: help_dkim_troubleshooting.php section on multi-signature scenarios documents the verifier behaviour in detail.
11. Monitoring: three surfaces
Rule 11: monitor DKIM via three complementary surfaces.
Surface 1: DMARC aggregate reports.
Every receiver that ingests mail from your domain
emits a daily aggregate report to the rua=mailto:
address you publish in your DMARC record. The
<auth_results><dkim>
blocks contain the verdict for every received
message. Use DMARC Analyzer to ingest these
reports and surface the per-selector pass/fail
profile in the dashboard.
What to alert on:
- Sudden drop in dkim=pass rate (any selector falling below its 30-day baseline by >5 percentage points).
- Rise in dkim=fail (forwarder/mailing-list body modification — investigate ARC sealing or per-receiver policy).
- Rise in dkim=permerror (DNS publication broken — investigate immediately).
- Rise in dkim=temperror (authoritative nameserver overloaded — investigate DNS provider).
Surface 2: Authentication-Results
header spot-check. Send a test message
from your domain to yourself; paste the raw
headers into the
Email Header
Analyzer. The receiver-side verdict string
(dkim=pass header.d=example.com) is
the ground truth — aggregate reports lag by 24
hours, headers are immediate.
Surface 3: DNS monitoring.
Alert on TXT-record changes at
<selector>._domainkey.<domain>
— any change is either authorized (rotation)
or unauthorized (compromise) and warrants
investigation within the same business day.
Cross-reference: help_dkim_failures_explained.php is the verdict catalogue documenting each Authentication-Results dkim= verdict in detail.
12. DNS publication discipline
Rule 12: publish DKIM TXT records with attention to four DNS-level details.
- Use multi-string chunking for 2048-bit RSA keys — the base64-encoded key is ~392 characters and exceeds the 255-octet character-string limit (RFC 1035 §3.3.14). Split into adjacent quoted strings; the resolver concatenates at lookup time. See help_dkim_dns_syntax.php for the chunking syntax.
- Strip the PEM banner — the
p=value contains the raw base64 only, not the-----BEGIN PUBLIC KEY-----/-----END PUBLIC KEY-----wrapper. Including the banner producesdkim=permerror. - No embedded whitespace —
the
p=value is a single continuous base64 string. Some legacy parsers reject embedded line breaks or spaces. - Verify from multiple resolvers
immediately after publishing —
dig +short selector._domainkey.example.com TXTfrom@8.8.8.8,@1.1.1.1,@9.9.9.9should all return identical output. Discrepancies between resolvers indicate propagation delay or authoritative-server inconsistency.
TTL: 3600 seconds (1 hour) is the conventional default — short enough for rotation but long enough to absorb traffic spikes without re-querying. Lower TTLs (300 seconds) are acceptable during planned rotation windows.
Cross-reference: help_dkim_dns_syntax.php documents the full TXT-record syntax including the 255-octet chunking rule and the empty-p= revocation convention.
13. Emergency revocation: empty-p= within minutes
Rule 13: when a signing key is
compromised (private key leaked, signer
infrastructure breached, supply-chain attack
detected), publish an empty
p= at the affected selector WITHIN
MINUTES of detection.
The empty-p= form:
; Compromise detected — publish immediately:
selector1._domainkey.example.com IN TXT "v=DKIM1; k=rsa; p="
Receivers MUST treat any signature referencing
this selector as dkim=permerror per
RFC 6376 §3.6.1. The structurally critical
detail: DO NOT DELETE THE RECORD. Deletion
produces NXDOMAIN at resolvers, which some
verifiers interpret as transient (DNS outage)
and retry with dkim=temperror. The
explicit empty-p= form tells every receiver
"this key is permanently revoked, do not
accept any signature using it".
Post-revocation playbook:
- Publish empty-p= (within minutes).
- Stand up a new selector with a fresh keypair, switch signer to use it.
- Document the incident: detection time, scope of suspected forgery, customer notifications.
- Keep the empty-p= record for at least 30 days for in-flight messages.
- Audit other selectors for the same compromise vector.
Cross-reference: help_dkim_key_rotation.php documents the emergency-revocation playbook alongside the routine-rotation cadence.
14. Documentation and change management
Rule 14: maintain a per-selector change log with four fields per entry.
- Selector name — e.g.,
sel-2026a. - Deployment date — when the selector was first published in DNS.
- Rotation history — every switch-in and switch-out date for this selector.
- Owner — the team or on-call responsible for this selector.
The minimum-viable change log is a plain Markdown file in your infrastructure-as-code repository:
# DKIM selector change log — example.com
| Selector | Deployed | Switched in | Switched out | Revoked | Owner |
|----------------|-------------|--------------|--------------|--------------|-------------|
| sel-2024a | 2024-01-08 | 2024-01-15 | 2025-01-15 | 2025-02-14 | infra |
| sel-2024b | 2024-06-08 | 2024-06-15 | -- | -- | infra (M365) |
| sel-2025a | 2025-01-08 | 2025-01-15 | 2026-01-15 | 2026-02-14 | infra |
| sel-2026a | 2026-01-08 | 2026-01-15 | -- | -- | infra |
| sel-2026b-ed25519 | 2026-05-22 | 2026-05-29 | -- | -- | infra (ed25519 dual-publish) |
The log provides three operational guarantees: (1) auditability — every selector that has ever existed is documented with its provenance, (2) rotation evidence — a quarterly compliance review can verify the annual rotation cadence is being honored, (3) incident-response context — when a selector is implicated in a forgery investigation, the log immediately surfaces the responsible team and the deployment-period blast radius.
15. Quarterly cluster audit checklist
Rule 15: run a quarterly cluster audit — verify every rule above against every production selector.
The audit script (manual or automated):
- Enumerate every production selector by inspecting the DKIM change log AND by surveying DMARC aggregate reports for selectors actually observed in the wild (the log may be incomplete; the reports are ground truth).
- Verify key size — every RSA selector returns a 2048-bit key. Flag any 1024-bit residual.
- Verify k= — is the key type documented? Is ed25519 dual-publish in progress where applicable?
- Verify no stale t=y — no production selector should carry the testing flag.
- Verify no l= in emitted signatures — capture a recent outbound message and inspect the DKIM-Signature header.
- Verify oversigned From, Subject, Date — same captured signature.
- Verify TXT chunking — 2048-bit keys should render as multi-string in the zone file; if represented as a single string, check whether the DNS provider auto-chunks correctly.
- Verify multi-resolver resolution — every selector resolves identically from Google, Cloudflare, and Quad9.
- Verify DMARC aggregate verdict distribution — every selector has a healthy pass rate; flag anomalies.
- Verify rotation cadence — no selector older than 12 months still actively signing.
Document audit findings, file follow-up issues for any rule violations, and re-run the audit quarterly.
FAQ
- What is the single most important DKIM best practice?
- Use 2048-bit RSA as the floor for every DKIM signing key, per RFC 8301 §3. 1024-bit RSA is computationally broken at the resources available to a determined adversary (forgery in days on a commodity GPU cluster), and modern receivers — Gmail, Microsoft 365, Yahoo, AOL, ProtonMail — downgrade verdicts on 1024-bit keys to dkim=policy or treat the signature as dkim=fail outright. Any DKIM deployment still using 1024-bit RSA in 2026 has effectively no anti-forgery protection regardless of how correctly the rest of the configuration is wired. The 2048-bit minimum is the single rule that, if violated, makes every other best practice irrelevant. If you have ANY production selector still publishing a 1024-bit key, rotate it to 2048-bit during the next planned change window using the dual-selector overlap discipline documented in help_dkim_key_rotation.php.
- How often should I rotate my DKIM signing keys?
- Once per year is the modern operator-discipline standard. The threat models change over time: cryptographic primitive degradation (the 2024-2026 wave of CRQC-prep advisories), accidental private-key exposure (developer laptop compromise, CI/CD secret leak, supply-chain breach in a build pipeline), and operational hygiene (a yearly rotation cadence forces the deployment to keep working, exercising every part of the rotation pipeline at least once per year so it never atrophies). Use the dual-selector overlap discipline: stand up the new selector, publish it in DNS, wait 7 days for cache propagation, switch the signer to the new selector, wait 30 days for in-flight messages to drain, then revoke the old selector with empty-p= for another 30 days before removing entirely. Total rotation lifecycle is 67 days end-to-end. The full sequence is in help_dkim_key_rotation.php. Emergency rotation (key compromise detected) skips the 7-day overlap and publishes empty-p= immediately at the affected selector.
- Should I sign messages with multiple DKIM-Signature headers?
- In most cases, no — a single well-configured DKIM signature is enough and adds the least operational complexity. Multiple signatures make sense in two narrow scenarios: (a) a sub-brand structure where different mailboxes legitimately use different signing keys (e.g., support@example.com signed by one tenant, newsletter@example.com signed by another) — but this is better handled with selector isolation under a single d= value than with multi-signature; (b) algorithm transition during the multi-year k=rsa to k=ed25519 migration — dual-publish both keys at separate selectors and let the signer add both, so receivers that have not implemented RFC 8463 fall back to the RSA signature. For DMARC alignment, RFC 7489 §3.1.1 says "any aligns wins" — if any of the dkim=pass results has an aligned d=, DMARC alignment is satisfied. So multi-signature does provide alignment robustness, but the operational complexity (DNS publication, monitoring, rotation coordination) is rarely worth it unless you are explicitly running an algorithm migration. Default to single-signature; add multi-signature deliberately for a documented use case.
- What canonicalization mode should I use?
- Use c=relaxed/relaxed (the c= tag in the DKIM-Signature header sets canonicalization as <header>/<body>). The relaxed/relaxed mode tolerates the kinds of body modifications that legitimate intermediaries routinely make: trailing whitespace removal, blank-line collapse, line-ending normalization. The simple/simple mode is intolerant of any modification — any whitespace change anywhere in the body produces a body-hash mismatch. In practice, modern mail traffic passes through too many intermediaries (forwarders, mailing lists, content-scanning gateways, anti-spam appliances) for simple/simple to survive — every modern operator deployment uses relaxed/relaxed and accepts that ARC sealing (RFC 8617) is the proper structural fix for the residual body-modification cases. The full canonicalization deep dive is in help_dkim_canonicalization.php. NEVER use simple/simple for new deployments; if you inherit a simple/simple configuration, migrate to relaxed/relaxed during the next routine rotation.
- Which headers must my DKIM signer include in the h= list?
- At minimum, h= must include From: (RFC 6376 §5.4 mandates From signing — a signature without From in h= is non-compliant and most receivers reject it). Beyond From, the standard operator-discipline list adds: Subject, Date, To, Reply-To, MIME-Version, Content-Type, Content-Transfer-Encoding, Sender. These are the headers a forger would manipulate to mount a spoofing attack; signing them ties their values to the cryptographic verdict. ADDITIONALLY: oversign From, Subject, and Date with the empty-double-list trick — h=From:Subject:Date:From:Subject:Date — which signs ANY appearance of those headers including future-added copies. The oversigning defense neutralizes the attack where a forwarder adds a SECOND From: header above the signed one; receivers that read the first From: see the unsigned forged header but the signature does not protect against the augmented set. Oversigning From/Subject/Date is documented in help_dkim_signatures_explained.php as the "Hashed Header Field" defense.
- Is the l= body-length tag safe to use?
- No. The l= tag declares that only the first N body bytes are covered by the signature; everything after byte N is unsigned and a replay attacker can append arbitrary content (phishing CTAs, malware links, drive-by JavaScript) to your signed message and the signature still verifies. RFC 6376 §3.5 itself cautions against l= use; the cryptographic community classifies it as a known replay-attack vector. The l= tag exists in the RFC because the original DKIM design contemplated signing very large bodies with a limit, but the security cost has always outweighed the operational benefit. Modern signing libraries do not emit l= by default; if you find l= in your DKIM-Signature output, audit the signer configuration and remove it. The full l= threat model is documented in help_dkim_replay_attacks.php with concrete attack scenarios. NEVER deploy l= in production.
- When should I use the t=y testing flag and when must I remove it?
- Use t=y for the first 24 to 72 hours after deploying a NEW selector. The flag signals to verifiers that the key is in deployment-test mode — verifiers SHOULD compute the verdict (so it appears in Authentication-Results headers for your inspection) but SHOULD NOT feed it into DMARC alignment, spam filters, or reputation scoring. This lets you debug the cryptography (selectors resolving, signatures verifying) without affecting deliverability. Once aggregate reports confirm a healthy verdict pattern (dkim=pass on every receiver, no dkim=permerror, no dkim=fail spikes), REMOVE t=y. Leaving t=y in production is one of the top three causes of "DKIM is configured but DMARC still fails" tickets — every receiver downgrades the resulting dkim=pass to "pass but ignore", which silently disables DKIM-based DMARC alignment even though the cryptography is perfect. The discipline: set a calendar reminder for 72 hours after every new selector deployment specifically to remove t=y.
- How should I monitor my DKIM deployment for regressions?
- Combine three monitoring surfaces. (1) DMARC aggregate reports: the rua=mailto: address receives daily XML reports from every receiver that ingested mail from your domain — the <auth_results><dkim> blocks contain the verdict for every received message. Use DMARC Analyzer to ingest these reports and surface the per-selector pass/fail profile in the dashboard. A sudden drop in dkim=pass rate or rise in dkim=fail / dkim=temperror is a regression signal. (2) Spot-check Authentication-Results headers on outbound mail you receive from your domain (send a test to yourself, paste into the Email Header Analyzer) — the receiver-side verdict string is the ground truth and surfaces issues that aggregate reports miss (e.g., temperror caused by your authoritative DNS being slow). (3) DNS monitoring: alert on TXT-record changes at <selector>._domainkey.<domain> — any change to the published key is either authorized (rotation) or unauthorized (compromise) and warrants investigation. The dashboard cross-reference is documented in help_dkim_troubleshooting.php.
- Should I sign with k=rsa or k=ed25519?
- In 2026, sign with BOTH on separate selectors and let the signer choose which one to use per message. ed25519 (RFC 8463) has structural advantages — 32-byte public keys, 64-byte signatures, faster verification, no key-size choice to get wrong — but is less universally supported. A receiver that has not implemented RFC 8463 (less common in 2026 but still present in older spam appliances and small ISPs) produces dkim=neutral or dkim=permerror on ed25519 signatures. RSA with 2048-bit keys (RFC 8301 §3) is universally supported but operationally heavier (larger TXT records requiring 255-octet chunking, slower verification, looming concerns about CRQC quantum-resistance in the late 2020s). The dual-publish posture: selector1._domainkey publishes the RSA key (k=rsa, p=<2048-bit-base64>), selector2._domainkey publishes the ed25519 key (k=ed25519, p=<32-byte-base64>). The signer adds both signatures or alternates per message; the verifier picks whichever it understands. Over time, as receiver coverage of ed25519 reaches parity, the RSA selector can be deprecated. The cryptographic background is in help_dkim_cryptography_basics.php.
- What is the proper way to revoke a compromised DKIM signing key?
- Publish an empty p= at the affected selector immediately, then rotate the signer to a new selector with a fresh keypair. RFC 6376 §3.6.1 specifies that an empty p= value is the canonical "permanently revoked" signal — receivers MUST treat any signature using this selector as dkim=permerror. The empty-p= record is structurally different from deleting the record entirely: deletion produces NXDOMAIN at resolvers, which some verifiers interpret as transient (DNS outage) and retry with dkim=temperror. The empty-p= form explicitly tells every receiver "this key is gone, do not accept any signature using it". Keep the empty-p= record for at least 30 days (one mail-archive lifetime for forwarded messages still in flight) before removing entirely. The detailed revocation playbook with timing, parallel signer rotation, and post-compromise audit checklist is in help_dkim_key_rotation.php. Never wait, never debate — when a key is compromised, the empty-p= publish happens within minutes of detection.
Audit your DKIM deployment now
DMARC Analyzer ingests every aggregate report and surfaces the per-selector verdict distribution in the dashboard — the most efficient surface for executing Rule 11 (monitoring) and Rule 15 (quarterly audit) of this best-practices checklist.