sfw/fix
dkim=fail (bh) high

DKIM Fail: Body Hash Did Not Verify (bh= Mismatch)

DKIM failed because the receiver's recomputed body hash does not match the signed bh= tag — the body changed after signing.

What you see

dkim=fail (body hash did not verify) header.d=example.com header.s=selector1 Authentication-Results: mx.google.com; dkim=fail reason="body hash did not verify"

What’s actually happening

Authentication-Results headers show dkim=fail with the reason 'body hash did not verify', even though the DKIM record is published correctly and the signature itself is well-formed. A mismatched body hash often breaks DMARC alignment and pushes mail to spam or a reject. The classic tell: direct mail passes DKIM, but the same mail sent through a mailing list, a security gateway, or a forwarder fails. The signature (the header hash) can still verify while only the body hash is wrong.

Common causes

  • A mailing list (Mailman, Google Groups, LISTSERV) appended an unsubscribe footer to the body after your server signed it.
  • Your own ESP or appliance adds a disclaimer/footer *after* DKIM signing, so the signed body no longer matches what goes out.
  • A link-wrapping or click-tracking gateway rewrote URLs in the body in transit, changing the bytes the receiver hashes.
  • A receiving or relaying gateway/scanner performed MIME conversion or re-encoding (e.g. 8bit to quoted-printable), altering the body.
  • Simple/simple canonicalization is in use, so trivial whitespace or line-ending changes by any intermediary break the hash; or a fragile l= length tag is set.

How to fix it

  1. Make DKIM signing the last step before sendRe-order your pipeline so nothing modifies the message after signing. If a footer, disclaimer, or banner is applied by a gateway or ESP, that step must run *before* DKIM signs, not after. This is the single most effective fix and removes most footer-related bh failures.
  2. Switch to relaxed body canonicalizationIn your signing config set c=relaxed/relaxed instead of simple/simple. Relaxed tolerates whitespace and line-ending normalization that intermediaries routinely apply, so harmless reformatting stops breaking the body hash. This is the sane default for most deployments.
  3. Remove the l= (body length) tagIf your signatures include an l= tag, drop it. It was meant to survive appended footers but it opens a content-injection hole and still fails when the body before the cutoff changes. Sign the whole body with no length limit.
  4. Account for mailing lists with ARC or list-side signingForwarders and lists that must modify the body will break your original DKIM by design. Have the list re-sign with its own DKIM, and rely on ARC so downstream receivers can trust the list's record of your original pass. You cannot keep your own DKIM intact through a body-mutating list.
  5. Capture and diff the delivered bodyPull the raw delivered message (Show original in Gmail, or the .eml from the receiving server) and compare it byte-for-byte against what you sent. The diff — an added footer, rewritten links, a re-encoded part — points straight at which hop is mutating the body so you can fix or reorder that specific step.

Stop it recurring

Sign last, use relaxed/relaxed canonicalization, never set l=, and test every outbound path including lists and gateways so a body-rewriting hop cannot silently break your body hash.

Related errors