The short answer: dkim=fail means the receiver found a DKIM signature but could not verify it. The message body or signed headers changed after signing (body hash or signature mismatch), the public key is missing or wrong in DNS, or the key has expired or been revoked. dkim=none means no signature was present. The exact reason is in the text beside the result.
A DKIM result in your headers is one line, but the wording beside it tells you which of several quite different problems you have. This guide starts with how to read that line, then goes through each cause with the fix, using sample headers. Wording varies between receivers, so the examples below are illustrative, not word-for-word output from any one provider.
New to the protocol? Read SPF, DKIM, and DMARC explained first.
Step 1: Find the Result and the Reason
Open a received copy of the message and view the raw headers (Gmail: three-dot menu, then Show original; Outlook: File, Properties, Internet headers). Find Authentication-Results:
Authentication-Results: mx.google.com;
dkim=neutral (body hash did not verify) header.i=@yourdomain.com header.s=google header.b=Xk3Qp1aZ;
spf=pass smtp.mailfrom=yourdomain.com;
dmarc=pass (p=NONE) header.from=yourdomain.com
Then find the DKIM-Signature header the sender added:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yourdomain.com;
s=google; t=1759660800; h=from:to:subject:date:message-id:mime-version;
bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=;
b=Xk3Qp1aZ...
The tags that matter:
| Tag | Meaning |
|---|---|
d= |
Signing domain. DMARC alignment compares this to the From domain |
s= |
Selector. The key is looked up at s._domainkey.d in DNS |
h= |
Header fields covered by the signature |
bh= |
Hash of the body at signing time |
b= |
The signature itself |
c= |
Canonicalisation (relaxed tolerates whitespace changes; simple does not) |
t=, x= |
Signing time and optional expiry |
To decode the whole header chain quickly, paste it into the email header analyzer; to test the DNS side, use the DKIM checker with the selector from s=.
Step 2: Match the Wording to the Cause
| What you see | Meaning | Most likely cause | Go to |
|---|---|---|---|
dkim=none / message not signed |
No signature added | DKIM not enabled for this sender | Cause 1 |
no key for signature / key not found |
Selector lookup returned nothing | Wrong selector, record missing or on the wrong host | Cause 2 |
body hash did not verify |
Body changed after signing | Footer, disclaimer or rewriting after signing | Cause 3 |
signature verification failed / bad signature |
Signature does not match the key | Key mismatch, or signed headers altered | Causes 4 and 5 |
key revoked / empty p= |
Key explicitly withdrawn | Old record left with an empty key | Cause 6 |
signature expired |
x= time has passed |
Delayed delivery or an old message re-sent | Cause 6 |
dkim=pass but dmarc=fail |
Signed, but not aligned | d= is a vendor's domain, not yours |
Cause 7 |
Cause 1: DKIM Is Not Enabled (dkim=none)
Many providers do not sign with your domain until you turn it on.
Google Workspace: Admin console, then Apps, then Google Workspace, then Gmail, then Authenticate email. Select your domain, generate a record (the default selector is google), publish the TXT record, then click Start authentication. The setting is per domain, so check each one.
Microsoft 365: Defender portal, then Email & collaboration, then Policies & rules, then Threat policies, then Email authentication settings, then the DKIM tab. Select the domain and enable signing. Before enabling you publish two CNAME records, selector1._domainkey and selector2._domainkey, pointing at Microsoft-hosted targets shown on that page.
Other platforms: look for "domain authentication" or "DKIM" in the sender or domain settings and publish exactly what is shown. Selector names and record types vary by vendor, which is covered in the third-party senders guide.
Cause 2: Wrong Selector or Missing DNS Record
The receiver looks up [selector]._domainkey.[domain] as a TXT record. If nothing is there, verification fails with a "no key" style message.
Typical mistakes:
- Record published at the root instead of under
_domainkey - Typo in the selector, or a selector that belongs to a previous provider
- Record created but never saved or published
- Record published as the wrong type (a TXT where the vendor required a CNAME, or the reverse)
- DNS host that appends your domain, producing
google._domainkey.yourdomain.com.yourdomain.com
Check with:
nslookup -type=TXT google._domainkey.yourdomain.com
You should see a value beginning v=DKIM1; k=rsa; p=.... If a CNAME is expected (as with Microsoft 365), look up the CNAME instead and confirm it resolves to a TXT record at the target.
Keep old selectors published after switching providers or rotating keys until delayed mail has cleared, otherwise messages signed under the old selector fail on arrival.
Cause 3: Body Hash Did Not Verify
This is the classic "email modified in transit" failure. The bh= value in the signature no longer matches the body the receiver sees. Common sources:
- Outbound disclaimers or footers added by a gateway, a transport rule or a third-party security tool after your platform has signed
- Mailing-list software that adds footers or subject tags
- Antivirus and content-filtering gateways that rewrite HTML or attachments
- Link-tracking or URL-rewriting applied on the way out by a different system from the one that signs
The fix is almost always about ordering: sign last. If a disclaimer tool must add text, make sure it runs before the DKIM-signing hop, or let the mail platform add the disclaimer itself. In Microsoft 365, mail flow rules that append disclaimers run before DKIM signing, so a body-hash failure there usually points to a third-party gateway outside Microsoft.
Avoid the old advice of using the l= (body length) tag so footers can be appended. RFC 6376 warns against it because it lets an attacker add content after the signed portion, and some receivers ignore or penalise signatures that use it.
For mail passing through lists or forwarders you do not control, DKIM can fail legitimately. ARC (Authenticated Received Chain, RFC 8617) lets intermediaries record the original result, and DMARC can still pass if SPF aligns, so avoid relying on one mechanism alone.
Cause 4: Public and Private Keys Do Not Match
The platform signs with a private key; DNS must contain the matching public key. They drift apart when:
- A new key was generated but the old public key is still in DNS
- You migrated mail platforms and carried the DNS record, not the key
- A vendor rotated keys and your DNS still has the earlier value
- The
p=value was pasted with a stray space or line break
The header then reads signature verification failed or bad signature even though a record exists. Compare the p= value in DNS with the current one in the platform's admin screen, character for character. If unsure, generate a new key in the platform and publish the replacement. If you need to format the record yourself, the DKIM generator builds it.
Cause 5: Signed Headers Were Altered
DKIM signs the headers listed in h=. If a hop rewrites one (most often From, To, Subject or Reply-To), the signature fails even though the body is intact. Typical culprits are mailing lists that prefix the subject, gateways that rewrite the From address for display-name or external-sender warnings, and aliasing services. Relaxed canonicalisation (c=relaxed/relaxed) tolerates harmless whitespace and header-case changes but not changed content.
Cause 6: Revoked, Expired or Truncated Keys
- Revoked key: a record with an empty value (
p=) tells receivers the key is withdrawn. Remove the revoked record or publish the new key. - Expired signature: if
x=is set, messages verified after that time fail. Long queue delays or old messages re-sent from an archive trigger this. - Truncated RSA-2048 key: a 2048-bit public key is longer than 255 characters, and a single DNS TXT string is limited to 255. It must be split into several quoted strings inside one record:
google._domainkey.yourdomain.com. TXT (
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxxxxxxxx"
"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" )
Most DNS hosts split automatically; a few require you to do it. If the value is cut off, verification fails every time. Falling back to a 1024-bit key fits in one string but is weaker, so prefer fixing the splitting. Microsoft 365's CNAME approach avoids the problem because Microsoft hosts the key.
Cause 7: DKIM Passes but DMARC Still Fails
A related problem looks like a DKIM failure but is not one:
Authentication-Results: mx.google.com;
dkim=pass header.i=@mail.vendor-platform.example header.s=k1;
dmarc=fail (p=QUARANTINE) header.from=yourdomain.com
The signature is valid, but d= is the vendor's domain, so it does not align with your From address, and DMARC counts only an aligned pass. The fix is to complete the vendor's domain authentication so it signs as d=yourdomain.com (or a subdomain, which relaxed alignment accepts). See DMARC policy levels for how failures are handled and reading DMARC aggregate reports to find which sources are affected.
What a Failure Costs You
The result depends on your DMARC policy and on whether SPF still passes with alignment. DMARC requires only one aligned pass, so a DKIM failure may be harmless when SPF aligns. At p=none failures are reported but not acted on. At quarantine or reject, mail that passes neither aligned check goes to spam or is blocked. Even with DMARC passing, repeated failures look bad to spam filters, so fix them. If mail is already landing in junk, see why your emails are going to spam.
Frequently Asked Questions
What is the difference between dkim=fail and dkim=none?
none means no DKIM signature was found on the message. fail means one was found but did not verify. Both are problems, but none points at setup, while fail points at DNS keys or modification after signing.
Does DKIM failure always send my email to spam?
No. DMARC needs only one aligned pass, so aligned SPF can rescue the message. Spam filters also weigh many other signals. But a persistent DKIM failure removes your safety net, so fix it before enforcing DMARC.
How long should I wait after publishing a DKIM record?
Usually minutes to a few hours, depending on TTL. Check the record directly with a DNS lookup or the DKIM checker instead of waiting a fixed number of hours.
Should I use a 1024-bit or 2048-bit DKIM key?
Prefer 2048-bit where your DNS host handles long TXT strings correctly. 1024-bit is still accepted widely but is weaker.
Can forwarding break DKIM?
Plain forwarding usually leaves DKIM intact because the message is unchanged. Mailing lists and gateways that edit the subject or body break it.
Next Step
Test your selector with the DKIM checker, or run the Email Security Score to see SPF, DKIM and DMARC together. For a written report, request a free email audit, or see the email security setup service if you want it fixed for you.