Defaults.Exposed › Rešenja › Guides
DKIM 'Body Hash Did Not Verify' — What Changed Your Message, and How to Fix It (2026)
Objavljeno 2026-07-08
Figures as of 2026-06-29 · methodology v7. Aggregate census data across 261 million graded domains. See how we grade.
“Body hash did not verify” means your DKIM signature was valid when the message left you — and something rewrote the message body afterwards. The signature isn’t broken; the message was modified in transit. Only 3.87% of domains — 10,092,481 — complete the full SPF-DKIM-DMARC triad, according to the Defaults.Exposed census of 261,086,232 domains (2026-06-29).
The fix is a hunt, then a decision. Find the hop that modifies your mail — a gateway appending a disclaimer, an appliance rewriting links, a mailing list adding a footer. Then sign after that hop, stop the modification, or make the signature tolerant of it — in that order.
What does “body hash did not verify” actually mean?
A DKIM signature (RFC 6376) carries two hashes: bh=, a hash of the message body as signed, and b=, which signs the headers plus that body hash. The verifier recomputes the body hash from the message it received; if it doesn’t match bh=, verification stops with the string everyone pastes into a search box — a receiver header like:
Authentication-Results: …; dkim=fail (body hash did not verify)
That’s Microsoft’s documented reason string; Gmail often renders the same diagnosis as dkim=neutral (body hash did not verify). Either way, the verdict narrows the problem enormously. Your DNS key, selector, and signing configuration are all fine. The cryptography did its job: the body changed between signing and verification — one appended line, one rewritten URL, one re-encoded character is enough. (A different message — signature did not verify, no key for signature — means a different failure; start with “DKIM signature not valid”.) And it’s urgent because a failed signature can’t give DMARC an aligned pass: unless SPF passes with alignment on the same message, the mail fails DMARC outright.
What changed your message? The usual suspects
Something in the delivery path edited the body after your signer sealed it. In practice it’s one of four things:
| Who modified it | What they change | Typical tell |
|---|---|---|
| Outbound gateway / smart host (Exchange transport rules, Mimecast, Proofpoint, Barracuda…) | Appends the legal disclaimer, marketing footer, or “EXTERNAL:” banner after the mail server already signed | Every message on that route fails; direct sends bypassing the gateway pass |
| Security appliance / link protection | Rewrites URLs to scanning redirects, adds tracking wrappers | Only messages containing links fail |
| Mailing list (Google Groups, Mailman…) | Adds a subject tag and list footer, sometimes reflows the body | Only mail sent through the list fails |
| Forwarder / relay re-encoding MIME | Transcodes charset, re-wraps lines — invisible to a human, fatal to a hash | Failures cluster on one recipient or forwarding address |
Check the bolded row first — the mail server signs, the edge device edits, and every message leaves with a signature that was true for thirty milliseconds.
How do I find the hop that’s modifying my mail?
Differential diagnosis — compare a path that works against the path that fails:
- Send a direct test message to a mailbox you control at a major receiver (Gmail works well), bypassing as much of your outbound chain as you can.
- Send a second message along the failing path — through the gateway, through the list, to the affected recipient’s domain.
- Compare the
Authentication-Resultslines in both full headers. Direct senddkim=pass, failing pathdkim=fail(ordkim=neutral) withbody hash did not verify: the modifier lives between those two routes. - Look at the received body: a disclaimer, banner, or footer you didn’t type? Links rewritten to a scanning domain? That’s your hop, named — and the
Received:chain shows which relay appears only in the failing path.
Your DMARC aggregate reports tell the same story at scale: a source consistently reporting DKIM fail with SPF pass is usually modification-in-transit on your own route, not an attacker.
How do I fix it?
- Run the free scan at defaults.exposed before touching anything. It confirms your published DKIM keys and DMARC policy are sound, so you’re debugging the one real problem — the modification — not chasing ghosts in DNS. The fix DKIM page covers the record-side checks.
- Sign after the modifying hop. The architecturally correct fix: move DKIM signing to the outermost device that touches the message. Exchange-plus-gateway shops should sign at the gateway (Mimecast, Proofpoint and peers all support it) and disable signing upstream. If Google Workspace or Microsoft 365 is your last hop, sign there and let nothing edit mail after it — see set up DKIM on Google Workspace or Microsoft 365.
- Or stop the modification. Take the edit out of the transport path: disclaimer in the client signature or template instead of a transport rule; “EXTERNAL:” banner scoped to inbound mail only (tagging your own outbound mail as external is a misconfiguration twice over); authenticated outbound mail exempted from link-rewriting.
- Use relaxed/relaxed canonicalization (
c=relaxed/relaxed).simplebody canonicalization fails on a single re-wrapped line;relaxedtolerates whitespace and line-ending changes. Be honest about the limit: relaxed forgives formatting, never content — an appended footer still fails, as it should. - Re-test both paths, then re-scan. Both routes should now show
dkim=passwith your domain ind=, and the scan report should be clean.
Should I use the l= tag to make DKIM ignore appended content?
No — and be suspicious of any guide that suggests it. The l= tag hashes only the first N bytes of the body, so an appended footer no longer breaks the signature. It “works” by leaving the end of your message unsigned: anyone holding a legitimate signed message can append arbitrary content and your valid signature still verifies over the result. That is a spoofing hole wearing a fix’s clothing — practical abuse has been demonstrated, and some receivers penalise or ignore l= for exactly this reason. Solve the modification; don’t unsign part of your mail.
What about mailing lists — can I fix those?
Mostly, no — and knowing that saves you weeks. A list that adds a subject tag or footer breaks your body hash by design, and you don’t control the list. Two things help:
- This residue is exactly why DMARC rollout is staged. Moving from
p=nonethroughp=quarantinewith apct=ramp, while reading aggregate reports, means list-mangled messages get quarantined rather than destroyed while you assess the impact — the subject of from p=none to p=reject without losing legitimate email. - ARC is the receiver’s mechanism, not yours. Authenticated Received Chain lets the list attest to what authentication looked like on arrival and the receiver decide whether to trust it. There is nothing for you, the sender, to configure. Well-run lists mitigate by rewriting the From header; poorly-run ones just break your mail.
Forwarding is the adjacent case — it reliably breaks SPF but only sometimes DKIM, which is why aligned DKIM is your forwarding-proof leg when the body survives: see forwarded email fails SPF — why you can’t fix it.
Why does DKIM break so often when so few domains even have the full stack?
Because DKIM is the fragile middle child of the triad: SPF is a static DNS record, DMARC a policy statement, but DKIM has to survive the journey. Only 51.84% of graded domains publish a discoverable DKIM key in DNS at all, according to the Defaults.Exposed census, and only 10,092,481 domains — 3.87% of 261,086,232 graded — hold SPF, DKIM and an enforcing DMARC policy together (the SPF adoption maturity model breaks the ladder down). Getting this fix right is the hardest part of joining that 3.87%.
Frequently asked questions
Is “body hash did not verify” a sign someone is spoofing my domain?
Usually not — a spoofer typically can’t produce your DKIM signature at all, so their mail shows no signature or no key. A failed body hash means a message genuinely signed by your infrastructure got edited afterwards. Check your own gateway before assuming an attacker.
SPF passes on these messages — am I still OK? For now, maybe: DMARC needs only one aligned pass. But SPF’s pass evaporates the moment anyone forwards the message, and if it isn’t aligned to your From domain it never counted for DMARC anyway. With only 3.87% of domains holding the full triad (2026-06-29 census of 261,086,232 domains), “one leg limping” is the normal state — and the fixable one.
Will switching to relaxed/relaxed canonicalization fix my disclaimer problem? No. Relaxed tolerates whitespace and line-wrapping changes only. An appended disclaimer is a content change, and the hash must fail on it — that’s DKIM working correctly. Move the signing point or move the disclaimer.
The failure only happens to one customer’s domain. Why? Their side almost certainly modifies inbound mail — a security appliance rewriting links or stamping banners before their verifier runs, or an internal forward re-encoding the body. Send them this page’s diagnosis section; the fix is on their gateway, not in your DNS.
Send the owner the report
If you’re fixing this for a client or your employer, close the loop with evidence. Once the modifying hop is fixed, re-run the free scan and forward the graded report to the business owner: dated, plain-language, DKIM and DMARC standing on one page. It’s the artefact they’ll need for the cyber-insurance renewal and the next supplier questionnaire — proof that the mail leaving the company is now the mail that arrives.
Check your domain → · “DKIM signature not valid” guide → · Fix DKIM → · How we grade → · Aggregate data only. Data stored and processed in the EU.