0 min left
DKIM "Body Hash Did Not Verify" - Causes and Fixes

DKIM "Body Hash Did Not Verify" - Causes and Fixes

BulkEmailSetup
BulkEmailSetup Team
August 23, 2026
4 min read

DKIM "body hash did not verify" means the receiving server hashed your message body and got a different value than the bh= field your server put in the DKIM-Signature header, so the body was modified after signing. The usual culprits are footers or disclaimers injected after the signing step, line-ending or whitespace rewriting by an intermediate MTA, and mailing lists that alter content. The fix is to sign last in your pipeline, use relaxed/relaxed canonicalization, and stop anything downstream from touching the body.

How the body hash works

When your MTA signs a message, it computes a SHA-256 hash of the (canonicalized) body and stores it as bh= inside the DKIM-Signature header:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yourdomain.com;
  s=mail2026; h=from:to:subject:date:mime-version;
  bh=2jmj7l5rSw0yVb/vlWAYkK/YBwk=; b=KxR3...

The receiver recomputes the body hash independently. If even one byte differs after canonicalization, you get dkim=fail (body hash did not verify), before the cryptographic signature (b=) is even checked.

The six real-world causes

CauseWho does itTypical symptom
Footer/disclaimer added after signingCompliance gateways, antivirus appliances, "scanned by" bannersFails on all mail through that gateway
Signing happens before content filtersMisordered milters in Postfix/EximFails only when a filter rewrites something
Line-ending or whitespace rewritingIntermediate MTAs, some proxiesIntermittent fails, fixed by relaxed canonicalization
Mailing list modificationsLists appending footers or tagging subjectsFails only for list traffic
Trailing-newline handling bugsCustom sending code, some librariesConsistent fail from one sending path
8-bit content converted to quoted-printableMTAs downgrading 8BITMIMEFails on messages with non-ASCII bodies

Diagnose it in five minutes

Send a test to Port25's reflector:

echo "test body" | mail -s "dkim test" [email protected]

The reply includes a full DKIM breakdown. Then send to a Gmail address, open Show original, and compare:

  • dkim=fail (bad signature) → key/DNS problem, not a body hash problem
  • dkim=fail (body hash did not verify) → body modified after signing

To find where it breaks, diff what you sent against what arrived. Save the raw outbound message from your MTA queue and the raw received copy, then:

diff <(sed -n '/^$/,$p' sent.eml) <(sed -n '/^$/,$p' received.eml)

The diff shows you the injected footer, rewritten line endings, or re-encoded content directly.

Fixes by cause

Sign last in the pipeline

DKIM signing must be the final step that touches message content. In Postfix with OpenDKIM, check that your content filters (amavis, rspamd, disclaimer milters) run before the signing milter in smtpd_milters/non_smtpd_milters order. If a disclaimer appliance sits after your signing server, move signing onto that appliance or sign after it relays.

Use relaxed/relaxed canonicalization

Canonicalization defines how much normalization happens before hashing:

ModeHeader handlingBody handling
simpleByte-exactByte-exact except trailing empty lines
relaxedCase-folds names, collapses whitespaceCollapses runs of whitespace, strips trailing line whitespace

simple/simple breaks the moment any MTA reflows whitespace. Set relaxed/relaxed, in OpenDKIM:

Canonicalization  relaxed/relaxed

This is the default recommendation for every production signer and eliminates the whitespace class of failures entirely. It cannot save you from injected content, though, a footer is real bytes, relaxed or not.

Force deterministic encoding

If bodies contain non-ASCII characters, encode them as quoted-printable or base64 before signing. If you sign an 8-bit body and a downstream hop without 8BITMIME support re-encodes it, the hash changes. Most modern MTAs handle this, but it still bites custom senders using raw sockets.

Accept that mailing lists break DKIM, and rely on ARC

Lists that append footers will fail your signature no matter what you do. That's by design: DKIM proves the message wasn't modified, and the list modified it. The list should re-sign with its own domain, and receivers increasingly use ARC to preserve the original authentication results across the hop.

Don't forget the DNS side

While debugging, confirm the public key matches the private key actually signing:

dig +short TXT mail2026._domainkey.yourdomain.com

A stale key after a rotation produces signature failures that look superficially similar, see DKIM key rotation done right for avoiding that.

Why this matters for DMARC

A body hash failure means dkim=fail, which means no DKIM alignment for DMARC. If SPF also fails or is unaligned (common after forwarding, where SPF always breaks), the message fails DMARC outright. At p=quarantine or p=reject, your own legitimate mail lands in spam or bounces. If DKIM is failing, fix it before tightening your DMARC policy, and make sure the rest of your stack is right with this SPF/DKIM/DMARC setup guide.

How BulkEmailSetup helps

Our dedicated SMTP servers sign with relaxed/relaxed canonicalization as the last step in the delivery pipeline, and we verify dkim=pass at Gmail, Outlook, and Yahoo before handing the server over. DKIM, SPF, DMARC, and PTR are all configured for you. See pricing for what's included.

Frequently asked questions

What does DKIM body hash did not verify mean?

The receiver recomputed the hash of the message body and it didn't match the bh= value in your DKIM-Signature header. Something modified the body after your server signed it, so DKIM fails.

Is body hash failure the same as a wrong DKIM DNS record?

No. A wrong or missing DNS key produces errors like 'no key for signature' or signature verification failure. A body hash error specifically means the body content changed in transit.

Can a mailing list or forwarder cause DKIM body hash failures?

Yes, it's one of the most common causes. Lists that append footers or rewrite subjects break the original signature. ARC and re-signing by the list are the standard mitigations.

Does relaxed canonicalization fix body hash failures?

It fixes failures caused by whitespace and line-ending changes, which are common with intermediate MTAs. It does not help when actual content is added, such as a compliance footer injected after signing.

How do I test whether my DKIM passes?

Send a message to a Gmail account and open Show original, it displays dkim=pass or dkim=fail with a reason. Port25's verifier ([email protected]) returns a detailed report including the body hash check.

Tags

DKIMbody hashdkim=failcanonicalizationemail authenticationdeliverability
BulkEmailSetup

Written by BulkEmailSetup Team

We help businesses set up their own bulk email infrastructure, dedicated SMTP servers, IP rotation, and full deliverability control. One-time setup, no monthly platform fees.

Ready to set up your email infrastructure?

Get dedicated SMTP servers, IP rotation, and expert support to scale your email sending.

View Pricing