dkim=fail (body hash did not verify)
The signature and key are fine. Something edited the message in transit.
What you are seeing
- dkim=fail (body hash did not verify) header.i=@example.com
- Authentication-Results: mx.google.com; dkim=fail (body hash did not verify)
- DKIM-Signature verification failed: body hash mismatch
What it means
DKIM signs a hash of the body (the `bh=` value) and a hash of selected headers. "Body hash did not verify" means the key was found and the signature parsed, but the body the receiver hashed is not the body you signed. One byte is enough.
This is a different failure from "no key for signature" (DNS problem) and from "signature did not verify" (the header hash, or a key mismatch). Body hash failures are almost always caused by something between you and the receiver rewriting the message.
Because DKIM failed, DMARC has to fall back to SPF alignment. If the message was also forwarded, SPF is gone too and DMARC fails outright.
Why it happens
- A mailing list or group appended a footer
- Discussion lists add unsubscribe footers and subject tags after signing. This is expected behaviour and the reason lists are told to rewrite the From header.
- An outbound appliance added a disclaimer
- Legal disclaimers, banners and "external sender" notices injected by a gateway after the signing step invalidate the body hash. Sign after the disclaimer is added, or add it before signing.
- Two things signed the same message
- A tool signs, then a gateway re-signs or re-encodes. The earlier signature no longer matches. Keep a single signing point per hop.
- Transfer encoding changed
- A relay converting 8-bit to quoted-printable, normalising line endings or re-wrapping long lines changes the bytes. `c=relaxed/relaxed` canonicalisation tolerates whitespace changes; it does not tolerate added content.
- Length-limited signatures
- A signature using the `l=` tag covers only the first N bytes. It survives appended footers but is a known security weakness, so prefer fixing the appending instead of adding `l=`.
How to fix it
- 1Confirm the key and selector are healthy. Run the check above with your selector. If the key itself is fine, you have ruled out DNS and confirmed this is a body-modification problem.
- 2Compare a direct message with a failing one. Send the same message to an address that receives it directly and to the path that fails. If only the second fails, the modification happens on that path.
- 3Send a test message and read the parsed result. Use the MailVakt inbox test: you get a one-time address, send a real message to it, and the headers and DKIM verification are reported over the raw bytes we received.
- 4Move signing to the last hop you control. Whatever appends content should run before signing. On a gateway, that means signing on egress rather than in the application.
- 5For lists, rely on the list's own From rewriting. A list that rewrites From to its own domain re-signs as itself and DMARC passes for the list. You cannot keep your own signature intact through a modifying list.
Questions
- Is body hash did not verify a DNS problem?
- No. The receiver found and used your public key. Compare it with "no key for signature", which is the DNS failure, and check the selector only to rule it out.
- Why does it only fail for some recipients?
- Because only some paths modify the message. Internal recipients, mailing lists and recipients behind a scanning gateway each take a different route, and only the modifying ones break the hash.
- Does the `l=` tag fix it?
- It hides it. `l=` signs only the first N bytes, so appended content is ignored — and so is content an attacker appends. Fix the signing order instead.
- Can I still pass DMARC with DKIM failing?
- Yes, if SPF passes and is aligned with your From domain. That only holds while the message is not forwarded, which is why a working DKIM signature matters.
Fix this from ChatGPT or Claude
MailVakt is an MCP server, so your assistant can run this check itself, read the findings and walk you through the DNS edit. Ask it:
“Mail from example.com fails DKIM with "body hash did not verify". Check the DKIM keys for the domain and tell me which middlebox is likely rewriting the body.”
- Claude: Settings → Connectors → Add custom connector, then paste
https://mcp.mailvakt.com/mcp. - Cursor and other MCP clients: add the same address as an MCP server. Setup details.
Checks are free and need no account. Sign in only to collect DMARC reports for a domain.