DKIM "body hash did not verify": finding what changed the message body
Run the free DKIM checker →This article is a how-to. The matching tool checks a live domain.
"Body hash did not verify" is one of the more useful DKIM errors, because it's specific. The DKIM key in DNS isn't the problem, and neither is the signature's math. The body of the message the receiver got isn't the body that was signed. Something between the signer and the receiver changed it. The job is to find that hop.
What the error means
RFC 6376 §6.1.3 describes verification in order. The verifier canonicalizes the body, hashes it, and compares the result with the bh= value in the DKIM-Signature header:
> If the hash does not match, the Verifier SHOULD ignore the signature and return PERMFAIL (body hash did not verify).
This check comes before the public-key check. So when you see this result, the receiver hasn't even got as far as evaluating the key. That's different from "signature did not verify," which means the body matched but the header-and-key check failed.
How much change breaks it
The c= tag sets body canonicalization, which is the second half of a value like c=relaxed/relaxed:
- Simple (RFC 6376 §3.4.3) only ignores empty lines at the end of the body. Any other change breaks the hash, including a single space.
- Relaxed (§3.4.4) also ignores trailing whitespace on each line, and collapses runs of spaces and tabs into one space. It does not tolerate added text, changed words, rewritten links or re-encoding.
If c= is absent, the default is simple/simple (§3.5). A signer using simple body canonicalization breaks more easily than it needs to.
The usual culprits
Footers, disclaimers and signatures added after signing. This is the most common cause in MSP environments. Typical sources:
- a Microsoft 365 or Google Workspace rule that appends a legal disclaimer, but only when the message was DKIM-signed upstream, before it reached the tenant. Examples: an on-premises server, or an app that signs its own mail and relays through Microsoft 365 or Google. When the tenant itself signs the mail, its own disclaimer rule isn't, by itself, a reason to expect this error.
- a third-party signature-management service that inserts signatures in transit
- an outbound gateway that adds a "scanned by" banner
If any of these run after the message was DKIM-signed, the body no longer matches. The fix is to make sure modification happens before signing, or that the hop that modifies the message also signs it with an aligned key.
Mailing lists. Lists commonly append an unsubscribe footer or a list banner. RFC 9989 §7.4 discusses at length how mailing lists interact badly with DMARC. A body hash failure on mail that went through a list is expected behavior, not a sender bug.
Content-transfer re-encoding. RFC 6376 §5.3 warns that 8-bit messages can be converted to 7-bit in transit, and "such conversions will break DKIM signatures." Signers SHOULD convert to quoted-printable or base64 before signing, and the signer "MUST sign the message as it is expected to be received." This often shows up with older on-premises applications, scanners and copiers that relay 8-bit mail.
Line endings. Bare CR or LF characters must be converted to CRLF before signing (§5.3). A custom application that signs first and lets a relay fix line endings afterward fails every time.
Link rewriting on the outbound path. Any service that rewrites URLs in outgoing mail after it's signed changes the body. Inbound link protection at the recipient's end normally runs after DKIM has been checked, so it's rarely the cause on the receiving side.
Finding the hop
- Send a test directly from the signing platform to a mailbox you control, bypassing any connector or gateway if possible. If DKIM passes there, the platform's signing is fine.
- Add hops back one at a time: the transport rule, the disclaimer service, the outbound gateway. The hop that makes it fail is the one modifying the body.
- Compare bodies. Save the received message source from the passing and failing paths and diff the bodies. Added lines or re-encoded parts are usually obvious.
- Check
c=in the DKIM-Signature header. If it'ssimplefor the body, ask whether the sender can userelaxed.
What about the l= tag?
DKIM has an optional l= (body length) tag that signs only the first part of the body, so content appended later doesn't break the hash. RFC 6376 §8.2 warns against it: it "enables attacks in which an intermediary with malicious intent can modify a message," and says signers "should be extremely wary of using this tag," while receivers "might wish to ignore signatures that use the tag." Don't treat it as a fix.
Forwarders and ARC
Where a trusted intermediary has to change messages, as mailing lists and some security gateways do, the Authenticated Received Chain (ARC, RFC 8617) lets it record the authentication results it saw before the change, so a later receiver can take them into account. Mimecast's documentation, for example, describes adding ARC headers to inbound messages. ARC only helps when the final receiver trusts that intermediary. It doesn't repair the original DKIM signature.
Why it matters for DMARC
DMARC (RFC 9989) uses a DKIM signature only if it verifies and its d= domain aligns with the From: domain. A body hash failure removes DKIM's contribution, and the message then relies on aligned SPF, which forwarding commonly breaks. For a domain at p=quarantine or p=reject, a disclaimer rule added after signing can quietly push legitimate mail into spam, or get it rejected.
Check the client's DKIM setup now
It probes common selectors plus one you type, follows CNAMEs, reports the RSA key length, and flags revoked keys. Use it to rule out key problems before you go looking for the hop that changed the body.
Founding Partner: $1,999, one time. Keep an eye on DKIM and DMARC across every client so a new disclaimer rule doesn't quietly break delivery. Founding Partner covers 50 client domains with full branding (logo and colors), weekly rescans and change alerts, unlimited Security Briefs (150 prospect scans a month), the Grow toolkit, the Policy library, a branded service menu, webhooks, the API, and MCP access (except quote drafts). If you later subscribe to Pro, you pay $299/mo instead of $399 for as long as that Pro subscription stays active. The offer is capped at 50 seats and closes on Dec 15, 2026, or when all 50 seats are claimed, whichever comes first. Proposals and the Service Library require Pro. Founding Partner is non-refundable, except that you're refunded if the seats run out before your payment can be fulfilled.
See Founding Partner details →
FAQ
- What does "body hash did not verify" mean?
- The hash of the message body the receiver computed doesn't match the
bh=value in the DKIM signature. The body changed after it was signed, or it was hashed with different canonicalization. - Is my DKIM key wrong if the body hash fails?
- Usually not. The body hash is checked before the key is used. A key problem shows up as "signature did not verify" or "no key for signature" instead.
- Do email disclaimers break DKIM?
- They do if they're added after the message is signed. Make sure disclaimers and signatures are added before DKIM signing, or that the hop adding them signs the message again with an aligned key.
- Does relaxed canonicalization prevent body hash failures?
- Only for whitespace changes. Relaxed tolerates trailing spaces and collapsed whitespace, but not added text, changed links or re-encoded content.
- Should I use the l= tag to avoid footer problems?
- RFC 6376 warns that
l=allows malicious content to be appended, and that receivers may ignore signatures that use it. It's not a recommended fix. - Why does DKIM fail only for mail sent to a mailing list?
- Lists often add footers or banners, which changes the body. That's a known interaction. ARC can help receivers that trust the list.