What is DKIM?
DKIM (DomainKeys Identified Mail, RFC 6376) is an email authentication standard that lets a sending domain cryptographically sign outgoing messages so receiving mail servers can verify two things:
- The message was authorized by the owner of the signing domain.
- The signed parts of the message — the body and selected headers — were not modified in transit.
DKIM works by combining standard public-key cryptography with DNS. The sender keeps a private key on the mail server and publishes the matching public key as a DNS TXT record. Every outgoing email gets a DKIM-Signature header that contains a hash of the message signed with that private key. Receivers fetch the public key from DNS and verify the signature.
DKIM doesn't encrypt the email and doesn't tell receivers what to do when verification fails — it only proves the message is authentic. The policy layer ("reject failures") is DMARC's job. SPF, DKIM, and DMARC are designed to be deployed together; you can read our overview of all three for the bigger picture.
How DKIM signing works
When your mail server sends an email, the DKIM signer does the following:
- Pick the headers to sign. Common choices:
From,To,Subject,Date,Message-ID,MIME-Version,Content-Type. TheFromheader must be signed — this is what links DKIM to DMARC. - Canonicalize the headers and the body so trivial whitespace differences on the receiving end don't break the signature. RFC 6376 defines two canonicalization modes:
simple(strict) andrelaxed(forgiving). Most modern setups userelaxed/relaxedbecause intermediary servers commonly rewrite whitespace. - Hash the body with SHA-256 and record the result in a
bh=tag. - Hash the canonicalized headers, sign that hash with the private key, and place the base64-encoded signature in the
b=tag. - Prepend a
DKIM-Signatureheader to the message and hand it off to SMTP.
Because the headers list (h=) and body hash (bh=) are both covered by the signature, any modification to a signed header or to the body invalidates the signature.
The DKIM-Signature header
A typical signed message contains a header like this:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=mail2025; t=1716491400;
h=from:to:subject:date:message-id:mime-version:content-type;
bh=jaT4xZl1Vh6oZkrhgBgD4ZkY7Jdfb8hQ+JeDV2KkUSk=;
b=Q5q0G3...d2zN1wA==
The important tags:
v=1— DKIM version (always 1 today).a=rsa-sha256— Signing algorithm.rsa-sha256is the universally supported default.ed25519-sha256is also defined (RFC 8463) but support is still uneven, so RSA remains the safe choice.c=relaxed/relaxed— Canonicalization for headers/body.d=example.com— The signing domain. This is the value receivers look up in DNS. It is also the value DMARC compares against theFromheader for alignment.s=mail2025— The selector. Combined withd=, it tells the receiver which DNS record to fetch:mail2025._domainkey.example.com.t=1716491400— Signing timestamp (optional).h=from:to:...— The headers covered by the signature.bh=...— Base64 hash of the canonicalized body.b=...— The actual signature.
Other tags you may see: i= (the agent or user identity, less commonly used), l= (signed body length — usually avoided because it allows trailing content to be appended without breaking the signature), x= (expiration timestamp), q=dns/txt (query method, always dns/txt in practice).
The DKIM DNS record
The public key lives in a TXT record at <selector>._domainkey.<domain>. For the signature above, the receiver looks up mail2025._domainkey.example.com and finds something like:
mail2025._domainkey.example.com. 3600 IN TXT
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...IDAQAB"
Tags inside the record:
v=DKIM1— AlwaysDKIM1. If present, it must be the first tag.k=rsa— Key type (rsaored25519). Defaults torsaif absent.p=...— Base64-encoded public key. An emptyp=means the key has been revoked; receivers must treat any message signed with it as failing.t=y(optional) — "Testing" flag. Receivers should not reject solely because a test-mode key fails. Useful while rolling out new keys; remove once you're confident.t=s(optional) — Strict mode; thei=domain must exactly matchd=.s=email(optional) — Service type, usuallyemailor*.h=sha256(optional) — Allowed hash algorithms.
The base64 p= value is long — a 2048-bit RSA key is about 392 characters of base64. Many DNS providers limit individual TXT strings to 255 characters, so the value is often split into multiple quoted strings. Receivers concatenate them. Don't split inside the base64 alphabet manually; let the DNS provider's UI do it, or use the documented multi-string syntax.
How receivers verify a signature
When a receiver sees a message with a DKIM-Signature header:
- Parse the header. Read
d=,s=,a=,c=,h=,bh=, andb=. - Fetch the public key from
<s>._domainkey.<d>via DNS. - Canonicalize the body the same way the signer did, hash it, and compare against
bh=. If they don't match, fail. - Canonicalize the signed headers, hash them, and verify the signature in
b=using the public key. If it doesn't verify, fail. - Pass the result —
dkim=pass d=example.com— to the DMARC evaluator and downstream filters.
A message can carry multiple DKIM-Signature headers. Only one needs to pass for DKIM to be considered "pass" for that domain. Receivers commonly stamp every result in Authentication-Results so you can see exactly which signature passed:
Authentication-Results: mx.google.com;
dkim=pass header.i=@example.com header.s=mail2025;
spf=pass smtp.mailfrom=bounce.example.com;
dmarc=pass header.from=example.com
Selectors and key rotation
The selector is just a label; you can pick any value. Common conventions:
- Date-based:
2025a,jul2025,2025q3. - Vendor-based:
google,mailchimp,postmark1. - Purpose-based:
marketing,transactional,support.
Selectors let you publish multiple keys at the same time — one per vendor, plus an old key during a rotation window. To rotate a key without downtime:
- Generate a new key pair and publish the new public key at
<new-selector>._domainkey.example.com. - Configure the mail server to sign with the new private key and the new selector.
- Leave the old selector's record in DNS for at least the longest delivery delay you reasonably expect — typically 7–14 days. Messages signed with the old key but delivered late will still verify.
- After the grace window, either replace the old record's
p=with an empty value (explicit revocation) or delete the record entirely.
How often should you rotate? NIST recommends rotating signing keys at least annually; many security teams rotate every 6 months. Always rotate immediately if you suspect the private key has been exposed (former employee with access, compromised server, backup leak).
DKIM and DMARC alignment
DKIM alone proves that some domain signed the message. DMARC adds the requirement that the signing domain must match the visible From header — this is called alignment.
Two alignment modes:
adkim=r(relaxed, the default): The DKIMd=domain must share an organizational domain with theFromheader. Sod=mail.example.comaligns withFrom: hello@example.com.adkim=s(strict): Thed=must exactly match theFromdomain.d=mail.example.comwould not align withFrom: hello@example.comunder strict mode.
This is why third-party senders often ask you to set up DKIM under your own domain (e.g. postmark1._domainkey.example.com) instead of signing with their domain. A signature from d=postmarkapp.com would verify cryptographically, but it would not align with From: support@example.com — so DMARC would fail.
Common DKIM breakage modes
Missing DNS record
The most common failure: the mail server is signing with selector s=mail2025 but no TXT record exists at mail2025._domainkey.example.com. The signature can't be verified, so DKIM fails and the message often falls back to SPF-only authentication. If SPF doesn't align either, DMARC fails.
Key too short
RSA keys shorter than 1024 bits are considered weak and rejected by major receivers (notably Gmail). The minimum acceptable size today is 1024 bits; the recommended size is 2048 bits. Anything you generate fresh should be 2048. If you inherited a 512- or 768-bit key from an old system, rotate it immediately.
Body modified in transit
Mailing lists, antivirus scanners, and footer-injecting forwarders can modify the body after signing. If the body hash no longer matches bh=, DKIM fails. This is one of the original motivations for ARC (Authenticated Received Chain) and for choosing relaxed body canonicalization.
Header rewrites that break the signature
If any signed header is modified by an intermediary — e.g. a mailing list rewrites Subject to add [List] — the signature fails. The mitigation is to sign fewer headers (only the essentials) or to deploy ARC at the boundary.
DNS truncation
A public key over 255 characters needs to be split into multiple quoted strings in the TXT record. Some DNS providers' UIs silently truncate or mangle the split. Check the record with dig +short TXT mail2025._domainkey.example.com after publishing.
Revoked but not removed
A record with an empty p= is an explicit revocation. If you publish an empty p= by accident (some panels do this when you "delete" a value), every signed message from that selector fails.
Misaligned d=
The signature verifies cryptographically (DKIM passes) but the signing domain doesn't match the From header (DMARC fails on alignment). This is the classic third-party-sender problem — see the next section.
Multi-vendor and shared-service setups
A typical business sends email through several services: a transactional provider (Postmark, Sendgrid), a marketing platform (Mailchimp, Customer.io), a CRM (HubSpot), a helpdesk (Zendesk), and the in-house mail server. Each needs its own DKIM setup if you want DMARC to align.
The standard pattern:
- Each vendor gives you a unique selector (often vendor-suffixed:
pm._domainkeyfor Postmark,k1._domainkeyfor Mailchimp). - The vendor either gives you a public key to publish or asks you to CNAME the selector to a record they manage (
pm._domainkey.example.comCNAME →pm.pm-bounces.example.com.dkim.postmarkapp.com). - The vendor signs with
d=example.comso it aligns with yourFromheader.
The CNAME approach is preferred where available because the vendor can rotate keys without your involvement — they update the target record, your CNAME stays the same.
One gotcha: every vendor signs with its own selector, so the Authentication-Results header will show different s= values for different messages. That's normal. As long as d= aligns with From, DMARC is happy.
Next steps
- Check your DKIM record for any selector — you'll see the key size, validity, and warnings about weak keys.
- Audit every sending vendor. Each one needs DKIM under your domain. Vendors without DKIM-on-your-domain support break DMARC alignment.
- Read our authentication overview for how DKIM, SPF, and DMARC fit together.
- Plan a rotation cadence. Annual rotation at minimum; biannual if you can. Set a calendar reminder.
- Read our DMARC migration guide to put DKIM to work blocking spoofers.