Part of the
DNS & Authentication category
Browse every SPF / DKIM / DMARC, PTR, MX, and bulk-sender guide in one hub — including the step-by-step setup paths and the free record-by-record validator.
See the DNS & Authentication category →What DKIM Is, and Why It Exists
Every modern mail flow relies on two complementary authentication arms: SPF, which verifies the sending IP for the envelope domain, and DKIM, which cryptographically signs the message itself and verifies content integrity with a public key published in DNS. Both arms feed DMARC, which asks the receiver to require at least one of them to align with the visible From: domain and tells the receiver what to do when neither does (none, quarantine, or reject).
DKIM is the more resilient arm. SPF fails when a message is forwarded — the forwarding server's IP is not in the original sender's SPF record — and the message loses SPF alignment at every hop. The DKIM signature, by contrast, travels with the headers. It survives forwarding, list-manager rewrites, and most intermediate scans because it is calculated over the headers and body in transit, not against the IP that delivered the message. A domain that signs with only SPF loses DMARC alignment for every forwarded recipient; a domain that signs with only DKIM survives forwarding unscathed.
A canonical DKIM public-key record looks like this:
google._domainkey.yourdomain.com TXT
v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOC...This says: here is a DKIM record (v=DKIM1), the public key is RSA (k=rsa), and the actual key (p=...) is a base64-encoded 2048-bit RSA public key. Every tag the record carries controls a different piece of the validation pipeline; the rest of this guide walks through each one.
The Full RFC 6376 Tag Reference
DKIM records are a semicolon-separated list of tag=value pairs, just like DMARC. Every RFC 6376 record carries v=DKIM1 and a p= public key as the two mandatory tags. Every other tag is context — what the signing platform chooses to publish alongside the key.
v=DKIM1 (required, version identifier). Every DKIM record must start with this literal v=DKIM1 version tag. Anything else — including an unknown version like v=DKIM2 or a missing v= entirely — is treated as a malformed record at the receiving hop and the record is ignored. This is the same gate-as-DMARC pattern: the version literal is the parse signal, not the spec name.
p= (required, public key). The p= tag holds the actual base64-encoded public key. An empty p= value (zero-length) is the RFC 6376 revocation signal — it tells the receiving MTA that the selector is permanently retired and any cached signatures against the old key should fail validation immediately. Always republish with p= as the last step of a key rotation handover to invalidate the old key.
k= (key type). The k= tag declares the key algorithm. RFC 6376 defaults to rsa when this tag is absent, so older platforms often publish a DKIM record with no k= tag. Modern practice publishes k=rsa explicitly for RSA. Receivers also accept k=ed25519 for Ed25519 keys, though universal Ed25519 support is still being adopted by all major mailbox providers.
h= (acceptable hash algorithms). The h= tag is a colon-separated list of hash algorithms the signer uses — typically h=sha256 in production. Receivers use this tag to identify algorithms they should accept; a mismatched h= value between the published record and the signature header is the dominant silent-failure mode for a sender that recently upgraded from sha1 to sha256.
s= (service type). The s= tag restricts the selector scope (default is * = all services). In practice most senders either publish s=email or omit the tag entirely. RFC 6376 also defines s=*.email for wildcard subdomain scope — useful when you publish a default._domainkey record that should be discoverable under any subdomain.
d= (signing domain). The d= tag is not published in the DNS TXT record — it is part of the DKIM-Signature header where the signature lives. The d= domain is what aligns with the visible From: domain for DMARC purposes. A signature with d=mail.yourdomain.com from a message with From: hello@yourdomain.com passes relaxed alignment because yourdomain.com is the shared organisational domain.
t= (timestamp flags). The t= tag inside the DNS TXT record sets deployment-time flags: t=y means this selector is in test mode (signatures should not be used by receivers for enforcement); t=s means the selector is now strictly enforced. Most production senders publish t=s once the selector has been validated.
x= (expiration). The x= tag declares when the record expires as a UNIX timestamp. It is rarely used in production — most providers opt to rotate keys manually and republish with the p= empty-string revocation pattern instead of relying on automatic expiration. A past-due x= value will cause the record to be treated as revoked by receivers when they parse the x= tag explicitly.
c= (canonicalization, in the signature header). The c= tag is not part of the DNS record — it lives in the DKIM-Signature header and controls how the body and headers are prepared before the signature is calculated. Format: c=relaxed/relaxed (body canonicalization / header canonicalization). relaxed is the recommended setting for any modern mail flow.
bh= / b= (body hash and signature, in the signature header). The bh= tag is the body hash (the SHA-256 digest of the canonicalized body); the b= tag is the actual signature (the encrypted SHA digest signing the canonicalized headers). These two values are what the receiver verifies using the published public key; a mismatch on either is what fails signature verification at the receiving hop.
Selector Naming Conventions and Wildcards
The selector is the free-form label that sits between your domain and _domainkey. The selector string is what changes between publishing zones and rotation cycles; the rest of the DNS record structure stays stable. Conventions:
Per-platform selectors. Use a unique selector for every sending platform that signs on your behalf —google for Workspace, k1 or s1for Microsoft 365, a vendor-provided selector for your ESP, and any short label for your own outbound relay. Per-platform selectors let each platform rotate its own keypair independently — a key compromise in your ESP's chain does not invalidate your Google Workspace selector.
Rotation selectors. When you rotate a keypair, publish the new key under a different selector (s2 next to s1) and configure your sender to switch over to the new selector. Do not republish the new key under the same selector as the old one without explicitly revoking the old — receivers may return whichever cached version they have first.
Wildcard conventions. RFC 6376 defines the * wildcard for the s= service-type tag in the DNS record; it is not part of the selector path itself, but a wildcard DNS record at *._domainkey.yourdomain.com is supported and lets a single published key apply to any selector that resolves to that wildcard. In practice this is rarely used — per-platform selectors give you more control, and most senders prefer explicit publication over wildcard discovery.
Subdomain scoping. A selector on a subdomain (a marketing selector at marketing.yourdomain.com published as default._domainkey.marketing.yourdomain.com) is a useful scoping technique when the marketing and transactional streams should be DMARC-isolated — the d= signing domain becomes the subdomain, not the apex, and a misaligned marketing signature does not drag the apex DMARC posture down.
Check your DKIM selector resolves correctly
Pick a selector (google, default, k1, s1, s2) and the free DKIM validator resolves the TXT record at <selector>._domainkey.<yourdomain>, parses every RFC 6376 tag, and returns a 0–100 score plus plain-English findings on key length, hash algorithm, canonicalization, and replay scope.
Public / Private Keypair Setup
Every DKIM signature is anchored to an asymmetric keypair: the mail server signs outgoing mail with the private key it holds, and the public key lives in your DNS so receiving mail servers can verify the signature. The private key never leaves your sending infrastructure; the public key is published at selector._domainkey.yourdomain.com. If the private key is leaked, any signature the platform produces for that selector must be treated as compromised — republish the old selector with p= (empty) immediately and rotate to a fresh keypair.
1024-bit vs 2048-bit vs Ed25519. RFC 6376 originally specified a 512-bit minimum, but modern mailbox providers and DMARC reports treat anything below 1024 bits as insecure. The current safe floor is 2048-bit RSA — Microsoft, Google, and Yahoo publish explicit recommendations for 2048-bit on new selectors, and many receivers flag messages signed with 1024-bit or smaller keys as suspicious or fail validation outright. 1024-bit keys still resolve but should be rotated to 2048-bit as a defensive upgrade. Ed25519 is supported by an increasing number of providers (Fastmail, ProtonMail, some ESPs) but is not yet universally accepted — verify support with your recipient list before switching off RSA.
Canonicalization (c=). The c= tag in the DKIM-Signature header controls how the message body and selected headers are prepared before the signature is calculated. simple/simple is byte-exact — the smallest modification invalidates the signature. relaxed/relaxed ignores minor whitespace shifts, header-line folding, and trailing whitespace differences. Most production ESPs default to relaxed canonicalization for both body and headers; relaxed is the recommended setting for any modern mail flow, especially when intermediate MTAs (mailing lists, corporate forwarders) might rewrite the message in transit.
Key rotation handshake. Rotate in four ordered steps. Step 1: generate the new keypair, publish the new public key under a fresh selector (s2 next to s1). Step 2: configure your sending platform to sign with the new selector. Step 3: wait for receiver cache windows to expire — at minimum the longest DNS TTL in your propagation chain plus the receiver cache window (typically 24–72 hours combined). Step 4: republish the old selector with empty p= (zero-length value) so the old key is permanently retired. Missing step 4 is the most common rotation mistake — the old key remains valid for replay attacks until the TTL fully expires.
Hash algorithm choice. h=sha256 is the current production default. Older implementations sign with h=sha1 — receivers still accept sha1 but most providers flag sha1-signed messages as shadow-signed (the signature validates, but the platform hint that the message is old). For new selectors, publish sha256 only; the bh= body hash and b= signature should both be sha256 in the DKIM-Signature header.
Alignment Semantics with SPF and DMARC
DKIM alignment is the DMARC requirement that the d= domain on the DKIM-Signature header (the signing domain your ESP publishes when it generates the signature) must match — or be a parent of — the visible From: domain in the message. Two arm states exist:
Relaxed alignment (adkim=r, the default) — the d= domain must match the visible From: domain or any parent of it. d=mail.yourdomain.com aligned with From: hello@yourdomain.com is a relaxed-mode pass because yourdomain.com is the shared organisational domain. This is the mode DMARC defaults to and the mode every modern sender should keep during ramp.
Strict alignment (adkim=s). The d= domain must be an exact string match to the visible From: domain. The same pair (d=mail.yourdomain.com vs From: hello@yourdomain.com) fails strict alignment because the strings differ. Most production senders keep the default relaxed mode — strict is appropriate only when every signing source uses the exact same domain in both d= and the From: header.
The canonical alignment failure: your ESP signs outbound mail with d=mailvendor.net because the platform is configured with its own domain by default. Signature validation passes — the public key at vendor._domainkey.mailvendor.net verifies the signature — but DMARC alignment fails because mailvendor.net is not a parent of yourdomain.com. The fix is to reconfigure the ESP to sign with a subdomain of your brand (d=mail.yourdomain.com) and publish the matching DKIM public key at default._domainkey.mail.yourdomain.com.
DMARC passes when EITHER SPF alignment passes OR DKIM alignment passes. Receivers do not require both — but production senders want both to pass for the resilience: SPF can break on forwarding, and DKIM signatures occasionally fail on intermediate rewrites. Configure both arms against the same brand subdomain so a single-arm failure does not break DMARC outright.
Common DKIM Pitfalls
Every DKIM failure mode in a production mail flow clusters into a small set of root causes. The diagnostic shortcut is to first resolve the public key record, then check the signature header on a real outbound message. The combination almost always points at the underlying cause.
Too-short key. A 512-bit or 1024-bit key signs but is flagged by the receiver as weakly signed — Microsoft in particular classifies the message into a lower trust signal bucket. Fix: rotate to 2048-bit on a fresh selector.
No p= value (record exists but no key). The selector TXT record exists but the p= tag is empty. This is the RFC 6376 revocation signal — receivers treat it as a permanent retirement. Verify you intended to revoke the selector; if not, set p= to a valid base64 public key.
Expired t= or x=. An x= timestamp already in the past, or a t=y tag never moved to t=s. Receivers that honour x= treat the record as revoked; receivers that honour t= may still reject the selector as in test mode.
Hash algorithm mismatch. The record declares h=sha256 but the signature header uses sha1 (or vice versa). This is the silent failure mode when an ESP recently upgraded its signing algorithm but the published record still declares the old hash. Fix: update the published h= list, then re-verify the signature on a real outbound message.
Body canonicalization mismatch. The ESP signs with c=relaxed/relaxed but the receiving MTA expects simple headers. This breaks after intermediate MTA forwards that introduce whitespace rewrites — the relay thinks it is safe but the signature was computed against a stricter canonicalization. Fix: set the canonicalization to relaxed/relaxed on both sides.
ESP signing with its own domain. The most reputation-damaging DKIM pitfall. d=mailvendor.net instead of d=mail.yourdomain.com — signature validates but DMARC alignment fails. Fix: configure the platform to use a subdomain of your brand as the signing domain and publish the matching public key.
Multiple selectors confused at rotation. You publish a new key under the same selector as the old one, expecting receivers to pick up the change. Some receivers cache and return whichever version they had when the message arrived first — and the old key, if private, is now indefinitely reachable. Always publish on a fresh selector and revoke the old one explicitly with p= (empty).
Provider Quirks — Gmail and Outlook
Both providers pass DKIM and align on the d= vs From: rule, but they impose slightly different expectations on how the selector path is structured and on what they treat as a parent domain.
Gmail. Gmail accepts subdomain alignment on the full apex — d=mail.yourdomain.com versus From: hello@yourdomain.com passes relaxed alignment cleanly. Gmail looks at the d= domain at the organisational-domain level (the registered domain), not at any arbitrary subdomain level. Confirm your sending platform publishes the correct d= value for Gmail before relying on relaxed alignment — Gmail Postmaster Tools will surface alignment failures as a separate signal from signature failures.
Outlook. Outlook is stricter on certain subdomain patterns — a subdomain one level deep(mail.yourdomain.com) aligns cleanly, but deeper-nested subdomains(like eu.mail.yourdomain.com) sometimes fail alignment on older Outlook infrastructure in receiving organizations that have not yet refreshed their MTA. Microsoft also reads DKIM in combination with PTR presence and the alignment-at-the-receiving-hop test — SNDS filter colour is gated on a passing DKIM alignment in addition to authentication pass.
Common misconfiguration patternsthat affect both: the ESP default d= domain not changed to a subdomain of your brand (canonical DMARC alignment failure); the selector._domainkey record published under the wrong subdomain (e.g. on a vanity subdomain that no ESP signs against); and rotated keys that did not follow the four-step handshake — receivers cached the old key and started failing signatures rather than picking up the new one. Use the free DKIM validator to confirm both the resolver side and then a real outbound check via the email header analyzer to confirm the header side.
Validate DKIM, SPF, and DMARC in one pass
DKIM alignment is the second arm of every deliverability gate — but it cannot enforce the alignment requirement on its own. Confirm DKIM, SPF, and DMARC together with the combined checker, then drill into the per-record details.
Rapid Triage Checklist
When DKIM regresses — in a failed signature in the Authentication-Results header, in a DMARC RUA report failing alignment, in a yellow SNDS colour shift, in a sudden drop in inbox placement on a transactional stream — walk this list. Each entry pairs a symptom with the concrete next action.
- The DKIM selector TXT record does not resolve. Publish it. The exact label is
selector._domainkey.yourdomain.com. The value starts withv=DKIM1and includes a base64p=value matching your ESP's published public key. - The DKIM public key is too short. Rotate to 2048-bit on a fresh selector (s2 next to s1), reconfigure your signing platform to use the new selector, republish the old selector with empty
p=to invalidate it. Allow 24–72 hours for receiver caches to expire. - Signature fails at the receiver. The base64
p=value does not match the actual private key your ESP is using. Confirm the public key was published without truncation or wrapped line breaks; some DNS providers break long TXT records across multiple lines and that breaks DNS parsing. Verify withdig TXT selector._domainkey.yourdomain.comfrom an external resolver and check the whole value parses back to one continuous line. - Signature passes but DMARC alignment fails. The d= signing domain in your DKIM-Signature header is not a subdomain of your visible From: domain. Configure your ESP to sign with a subdomain of your brand and republish the matching public key. Free audit at the DKIM validator.
- Record exists but p= is empty. You have either accidentally published a revocation p= value or you previously retired this selector and the receiver is now treating any signature against it as permanently invalid. Confirm intent; if not, restore a valid base64 public key.
- DKIM validates but signature still fails. Header rewrites by an intermediate MTA broke the signature. Switch canonicalization to relaxed/relaxed on both sides, then re-verify with a real outbound message.
- Multiple selectors publishing the same platform. Your ESP has rotated keys but the old selector is still resolving a valid key. Pin the ESP to one selector at a time — publish the new key on a different selector (s2 next to s1), switch the signing platform, then revoke the old one with empty p= to prevent replay.
- You are sending to Gmail / Yahoo at scale (~5,000+ / day). The 2024 bulk-sender bar requires DKIM alongside SPF, DMARC at p=none or stricter, a working List-Unsubscribe-Post header (RFC 8058), and a spam complaint rate below 0.1% in Postmaster Tools. A missing or failing DKIM at this volume triggers throttling at Gmail and full rejection at Yahoo. The full checklist is in the Gmail Bulk Sender Requirements guide.
- You want to verify DKIM on a delivered message. Run the message through the email header analyzer. The Authentication-Results header lists the dkim= pass / fail verdict alongside the header.d= signing domain and the selector the signature was generated against.