Canny Pigeons

Learn · Fixing a signature

dkim=fail: what the reason string tells you

dkim=fail is not one failure with one fix. It is the headline on at least five different problems, and the receiver almost always tells you which one — in a reason string most people scroll straight past. Read it first. The difference between "the message was modified in transit" and "your key is wrong" is the difference between a change you cannot make and a change you can, and they look identical until you look.

If you are diagnosing your own domain rather than a message you received, start with the free DKIM checker: it fetches the key at a selector you name and tells you whether what is published is usable at all.

Find the reason first

Every result lives in the Authentication-Results header the receiving server adds. In Gmail, open the message, choose "Show original"; in Outlook, "View message source". Look for the line that names the receiving domain:

Authentication-Results: mx.google.com;
       dkim=fail reason="body hash did not verify"
         header.i=@yourdomain.com header.s=selector1;
       spf=pass smtp.mailfrom=yourdomain.com;
       dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=yourdomain.com

Three things on that line matter. header.s= is the selector, which tells you which key was used — useful when a platform rotates keys or you run several senders. header.i= or header.d= is the signing domain, which is what DMARC alignment is judged against. And reason= is the one that picks your fix.

ResultWhat the receiver is sayingWhere the fix is
fail — body hashThe message changed after you signed itUsually not yours to fix
fail — signatureThe key does not match the signatureYour DNS or your platform
neutralThe signature could not be evaluatedHow the record was published
permerrorSomething is malformed beyond evaluatingYour record or your signer
temperrorThe key could not be fetched just nowNowhere — wait

"body hash did not verify"

This is the most common dkim=fail and the one people most often misdiagnose, because the instinct is to suspect the key. The key is fine. A DKIM signature contains a hash of the message body taken at signing time; the receiver recomputes that hash on what actually arrived and compares. A mismatch means the body changed on the way.

Something in the path rewrote it. The usual suspects, in rough order of how often they turn up:

When the modification happens outside your control — which is most of the time — there is no fix at your end, and that is the point of ARC: it lets a forwarder vouch that authentication passed before it made its change. What you can do is make sure DKIM is not carrying your DMARC alignment alone, because a domain relying on DKIM only will fail DMARC every time a list touches a message.

One thing not to do: the l= tag limits how much of the body the signature covers, which makes appended footers stop breaking it. It also lets anyone append arbitrary content to your signed message and have it still verify. Do not use it to make this error go away.

"signature verification failed" and bad signatures

Here the body arrived intact and the cryptography still did not check out, which points at the key rather than the message. Four causes cover nearly all of it:

Test what is actually published rather than what you pasted: the DKIM checker resolves the selector and reports whether the key parses and what size it is. A record that comes back short is the truncation case.

dkim=neutral and dkim=permerror

These two mean the receiver never got as far as a verdict. neutral is "there is a signature and I could not evaluate it"; permerror is "something here is malformed and no retry will help". In practice both point at the same short list:

Unlike a body hash mismatch, this one is entirely yours and entirely fixable. Confirm the selector from header.s= in the failing message, then check that exact name.

dkim=temperror

The receiver tried to fetch your public key and could not — a DNS timeout, a lookup failure, a nameserver that was briefly unreachable. It is temporary by definition and changing your configuration in response is how a working setup gets broken at two in the morning.

A single temperror is noise. A steady trickle across providers is a signal, and it is about your DNS hosting rather than DKIM: check that every nameserver for the zone answers for _domainkey names, and that nothing is rate-limiting queries. Watch for it in your aggregate reports rather than in one message.

When DKIM passes and DMARC still fails

Worth knowing before you spend an afternoon on a signature that was never the problem. DKIM verifying is not the same as DKIM aligning. DMARC compares the signing domain in d= against the domain in your From header, and a platform that signs with its own domain produces a message that is genuinely authentic and aligns with nothing:

dkim=pass header.d=sendingplatform.com
From: you@yourdomain.com          → dkim aligned: no

The fix is a signing domain of yours, which nearly every platform supports and calls custom or branded DKIM. That case has its own page, because the symptom — green checks and a red DMARC result — sends people looking in the wrong place: DMARC fails but SPF and DKIM pass. If instead both checks are red in your reports, the causes are different again and SPF and DKIM both showing fail covers them.

For how signing works underneath any of this — selectors, what gets hashed, why forwarding is survivable at all — see what DKIM is.

Free checks: DKIM checker DMARC checker SPF checker Report analyzer

See which senders are actually signing

Every source sending as your domain, with its SPF and DKIM results and whether either aligned — read from your real reports rather than a single test message. Free for one domain.

Start free