# DKIM fail body hash did not verify

> DKIM fail (body hash did not verify) means the body changed after signing, so the receiver's hash no longer matches bh=. Fix the path, not DNS.

A DKIM result of `dkim=fail (body hash did not verify)` means the receiving server recomputed the hash of the message body and it did not match the `bh=` value in your `DKIM-Signature`. The body was changed after signing, or the two sides canonicalized it differently. This is a verification failure in the message body, not a DNS or key problem, so the repair is to the sending path rather than your published record.

## Quick takeaways

- `bh=` is the signed hash of the canonicalized body, separate from the `b=` signature over your headers.
- The failure means the body the receiver saw differs from the body that was signed.
- The most common cause is content added after signing: footers, disclaimers, banners, link rewriting, or a gateway, list, or forwarder.
- A valid published key and a passing selector do not prevent this failure.
- Widening or adding the `l=` body-length tag is not a safe fix and weakens the signature.
- Validate by sending a fresh message through the same path and reading the new header.

## What does the failure mean?

When a mailbox provider verifies DKIM, it runs two separate checks. It recomputes a hash of the message body and compares it to the `bh=` tag, and it verifies the `b=` signature that covers selected headers. [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376.html) defines `bh=` as the hash of the canonicalized body and has the verifier recompute that hash and compare it to the signed value. When the two do not match, the body the receiver saw is not the body that was signed, and the provider reports `dkim=fail (body hash did not verify)`. Microsoft documents this exact result in a [Microsoft Q&A thread on the body-hash failure](https://learn.microsoft.com/en-nz/answers/questions/2237197/dkim-fail-%28body-hash-did-not-verify%29), where an Exchange Online rule added a disclaimer after signing.

This is different from two failures that look similar. A [DKIM alignment failure](/learning/why-does-my-dkim-signature-fail-alignment) happens when the signature is valid but the `d=` domain does not match the `From` domain. A [missing key](/learning/no-dkim-record-found) happens when DNS returns no usable key at the selector. Body-hash verification runs before alignment is evaluated, and it can fail even when the key resolves. For background on how DKIM signs a message, see [what DKIM is](/learning/what-is-dkim).

```text
Authentication-Results: mx.receiver.example;
  dkim=fail (body hash did not verify) header.d=example.com header.s=selector1;
  spf=pass smtp.mailfrom=example.com

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=example.com; s=selector1;
  h=from:to:subject:date;
  bh=BASE64_BODY_HASH_EXAMPLE=;
  b=BASE64_SIGNATURE_EXAMPLE=
```

![Sender computes bh over the body, an intermediary changes the body, then the receiver recomputes a different hash, so DKIM reports body hash did not verify.](/images/editorial/dkim-fail-body-hash-did-not-verify/dkim-fail-body-hash-did-not-verify-body-hash-flow.svg)

*Original Palisade diagram. DKIM signs a hash of the canonicalized message body (`bh=`). If any hop changes the body before verification, the receiver's recomputed hash no longer matches `bh=` and DKIM reports body hash did not verify. Based on [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376.html).*

## What usually causes it?

### Content changed after signing

DKIM signs the body as it exists at signing time. Anything that edits the body after that point changes the bytes the receiver hashes. Common examples are a marketing footer, a legal disclaimer, a safety banner, or link and URL rewriting applied downstream. The Microsoft case above is a clear example: an Exchange Online mail-flow rule appended a disclaimer after the message was signed. Whether a specific hop caused your failure is something you confirm from your own headers, not an assumption.

### An intermediary rewrote the body

A mailing list, a security gateway, or a forwarder can modify the body in transit. Lists often add headers and footers, gateways can rewrite links or inject scanning notices, and some forwarders re-encode content. Each of these changes the canonicalized body and breaks the hash, even though the original signature was valid when the message left you.

### A canonicalization mismatch

DKIM canonicalizes the body before hashing. [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376.html) defines a `simple` algorithm that tolerates only empty trailing lines and a `relaxed` algorithm that normalizes trailing and repeated whitespace. If the signer used `simple` body canonicalization, a single whitespace or line-ending change anywhere in transit fails the body hash. The `c=` tag records which algorithms were used for the header and the body.

### A body-length or encoding change

A change to transfer encoding, character set, or line endings alters the canonicalized body. If the signature uses the optional `l=` body-length tag, only the first counted octets are protected, so appended content is not covered and mismatches are easy to introduce. Widening `l=` is not a fix; see the FAQ below.

### The signer computed the hash incorrectly

Less often, the signing system itself produces a `bh=` that does not match the body it sends, for example when a proxy re-serializes the message between hashing and transmission, or when a signing bug truncates the body. Confirm this only after ruling out downstream modification, because a broken signer fails consistently across every receiver.

## How do I diagnose the failure?

### 1. Read the receiver-added Authentication-Results and DKIM-Signature

Start with the strongest evidence: the header the receiver added. [RFC 8601](https://www.rfc-editor.org/rfc/rfc8601.html) defines the `Authentication-Results` header field, which the verifying server adds within its trust boundary and where the `dkim=fail (body hash did not verify)` reason appears. Read the `d=`, `s=`, `c=`, and `bh=` values from the `DKIM-Signature` on the same delivered message so you know which signer and canonicalization were used.

### 2. Identify the modifying hop from the Received headers

Read the `Received` headers from bottom to top to reconstruct the path. Note every list, gateway, or forwarder between your signer and the reporting receiver. A body-hash failure that appears only after a specific hop points to a modification at that hop. This mapping is a diagnostic inference you confirm, not a fixed rule.

### 3. Reproduce with and without the suspected intermediary

Send the same message directly to a mailbox you control, then send it again through the suspected path. If the direct message passes DKIM and the routed message fails with the same `bh=`, the intermediary is changing the body. Compare the delivered bodies byte for byte if you can capture both.

### 4. Confirm the published key resolves

Rule out DNS so you do not chase the wrong cause. A body-hash failure is not a missing key, but confirming the key removes doubt. Use the [Palisade DKIM checker](/tools/dkim) to look up the published key at your selector. If the lookup returns no record at all, the problem is DNS and the [no DKIM record found guide](/learning/no-dkim-record-found) applies instead. A resolving key confirms the failure lives in the message body.

## How do I fix it?

### Make DKIM signing the last content-changing step

The narrowest repair is to sign after every system that edits the body. Because [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376.html) computes `bh=` at signing time, signing last guarantees the signed body matches the delivered body. Move DKIM signing to the final egress point so footers, disclaimers, and banners are already in place when the hash is computed.

### Stop or move the post-signing modification

If a rule, gateway, or list is editing signed mail, either disable that modification for the affected stream or move it ahead of the signing step. When a downstream service must change the body, have it re-sign the message after its change so the delivered body and the signature agree again.

### Match canonicalization and do not rely on l=

Confirm the signer and any re-signer use compatible canonicalization. `relaxed` body canonicalization tolerates whitespace normalization, while `simple` does not. Do not widen or add the `l=` body-length tag to tolerate appended footers: [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376.html) warns that a limited body length lets extra content be appended without breaking the signature, which weakens it instead of fixing the modification.

## How do I validate the repair?

Validate on the same path that failed. Send a fresh message from the affected application through the same route, including any list or gateway, then open the delivered message and read the new `Authentication-Results`. Confirm `dkim=pass` with the expected `d=` and `s=`. A single passing message proves the signer and delivered body now agree. Watch DKIM pass rates in your DMARC aggregate reports over the next few days to confirm the fix holds across all traffic, since the wider [email authentication](/learning/what-is-email-authentication-and-why-does-it-matter) picture evaluates alignment on top of this verification.

## Isolate every remaining DKIM break across your domain

You have fixed one signing order or one intermediary. A single header check does not show which other production sources or forwarding paths still change the body and fail DKIM across your domain, and a correct signer today can drift as new senders appear. Start by confirming the published key with the [Palisade DKIM checker](/tools/dkim); it inspects the key at your selector but cannot see the in-transit body change that broke the hash, which lives in the delivered message.

To find the other breaks without reading raw reports, Palisade's [DMARC Agent](https://docs.palisade.email/guides/fixing-authentication-issues/) analyzes your DMARC aggregate reports, raises prioritized tickets for SPF and DKIM authentication and alignment issues, and proposes the next policy stage for your team to review and apply. It does not rewrite messages, sign your mail, or change DNS on its own, so a human stays in control of every change. Stronger authentication supports better deliverability rather than promising inbox placement.

[Start with Palisade](https://app.palisade.email/signup?utm_source=palisade_learning&utm_medium=article&utm_campaign=dmarc_troubleshooting&utm_content=dkim-fail-body-hash-did-not-verify)

## Sources and further reading

- [RFC 6376: DomainKeys Identified Mail (DKIM) Signatures](https://www.rfc-editor.org/rfc/rfc6376.html)
- [RFC 8601: Message Header Field for Indicating Message Authentication Status](https://www.rfc-editor.org/rfc/rfc8601.html)
- [Microsoft Q&A: dkim=fail (body hash did not verify)](https://learn.microsoft.com/en-nz/answers/questions/2237197/dkim-fail-%28body-hash-did-not-verify%29)
- [Palisade: fixing email authentication issues](https://docs.palisade.email/guides/fixing-authentication-issues/)

## Frequently asked questions

### Is "body hash did not verify" the same as a DKIM alignment failure?

No. A body-hash failure means the receiver's recomputed body hash does not match `bh=`, so verification fails before alignment is even checked. A [DKIM alignment failure](/learning/why-does-my-dkim-signature-fail-alignment) is different: the signature verifies, but the `d=` domain does not match the `From` domain. Fixing the body hash restores verification, and alignment is a separate check on top of it.

### Can a footer or disclaimer really break DKIM?

Yes. DKIM signs a hash of the message body, so any text added after signing, including a footer, disclaimer, or banner, changes the bytes the receiver hashes and breaks the match. This is one of the most common causes. The fix is to add that content before DKIM signs, or to sign as the last step before the message leaves your infrastructure.

### Can I fix this by changing my DNS record?

No, not in the usual case. A body-hash failure is a message-body problem, not a DNS problem, and republishing the key or relaxing your DMARC policy does not stop the body from changing. Only fix DNS when a lookup shows the key itself is wrong or missing, which the [no DKIM record found guide](/learning/no-dkim-record-found) covers. Otherwise, repair the sending path.

### Should I use the l= tag to allow appended content?

Not recommended. The `l=` body-length tag limits how many body octets are signed, so content past that length is unprotected. [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376.html) warns that this lets extra content be appended without breaking the signature, which weakens it and invites tampering. Fix the modification instead of widening `l=` to tolerate it.

### Does forwarding cause body-hash failures?

Yes, it can. Mailing lists and forwarders often add footers, rewrite links, or re-encode content, and each change alters the canonicalized body so the receiver's hash no longer matches `bh=`. You cannot control a third-party forwarder, so treat these paths as expected body changes and confirm your own direct sending path signs and delivers an unmodified body.

### Will fixing the body hash make DMARC pass?

Only when DKIM is the identifier DMARC relies on. DMARC passes when SPF or DKIM produces an aligned pass, so restoring DKIM verification helps only if your `d=` domain aligns with the `From` domain. If you depend on DKIM alignment, fixing the body hash is necessary. If SPF already aligns and passes, DMARC may pass regardless, so check alignment separately.
