DKIM "signature did not verify": what failed and where to look

Run the free DKIM checker →This article is a how-to. The matching tool checks a live domain.

A DKIM failure in a header or a DMARC report rarely names the cause clearly. Usually you get dkim=fail, sometimes with a comment such as "signature verification failed" or "signature did not verify." That wording comes from RFC 6376, the DKIM standard, and it narrows things down more than it seems. This page explains what was checked, what failed, and the short list of causes worth looking at first.

What a verifier actually checks

RFC 6376 §6.1.3 describes verification in steps. After canonicalizing the message, the verifier:

  1. computes a hash of the body and compares it with the bh= value in the DKIM-Signature header. If they differ, it returns PERMFAIL (body hash did not verify). We cover that in a separate guide.
  2. uses the public key from DNS to check the b= signature against the hash of the signed headers. If that check fails, it returns PERMFAIL (signature did not verify).

So "signature did not verify" generally means the body matched but the header-plus-key check didn't. The cause is one of three things: the signed headers changed in transit, the key in DNS isn't the key the message was signed with, or the key record can't be used.

In the Authentication-Results header (RFC 8601), this usually shows as dkim=fail: the message was signed and the signature was acceptable to the receiver, "but they failed the verification test(s)." Look at header.d= and header.s= (selector) on the same line, which tell you which domain and key to check.

Cause 1: the DNS key doesn't match the signing key

This is the most common cause in MSP environments.

  • A key was rotated on one side only. The sending platform switched keys but DNS still has the old one, or DNS was updated for a key the platform hasn't started using.
  • The wrong value was pasted. A key copied from the wrong tenant or environment, or a stale CNAME target.
  • The key was truncated in DNS. A 2048-bit key won't fit in one 255-character TXT string. RFC 6376 §3.6.2.2 says the strings "MUST be concatenated together before use with no intervening whitespace." DNS panels that silently cut the value at 255 characters, or insert spaces when splitting, produce a key that parses but never verifies.

Check: query <selector>._domainkey.<domain> (the selector is the s= value). If it's a CNAME, as with Microsoft 365, SendGrid, Mailchimp Transactional, Zendesk and others, follow it and compare what's published with what the platform says it should be.

Cause 2: signed headers changed in transit

The h= tag lists the header fields that were signed. If any of them changed after signing, the signature breaks:

  • a gateway or relay tagging the Subject, such as [EXTERNAL], or rewriting the From: or Reply-To
  • a mailing list prefixing the Subject or rewriting From:
  • a forwarding service that rewrites headers

The c= tag sets how strict the comparison is. With simple header canonicalization, even whitespace changes break the signature. Relaxed tolerates whitespace and case changes, but not changed content. The default is simple/simple if c= is absent (RFC 6376 §3.5), so a sender that doesn't set c=relaxed/relaxed is more fragile than it needs to be.

Check: compare the failing message's signed headers with a copy sent directly to a mailbox you control. If a gateway is involved, test with and without that hop.

Cause 3: a key record that can't be used

These cases fail with a different PERMFAIL code, but many receivers report them all as "fail" or "permerror," so check them too:

  • No key at the selector: PERMFAIL (no key for signature), RFC 6376 §6.1.2. This often happens after a selector was deleted while the platform kept using it.
  • Empty p=: the key has been revoked, which is a failed check (§3.6.1, §6.1.2).
  • Key syntax error in the record (§6.1.2).
  • rsa-sha1 signatures or RSA keys under 1024 bits. RFC 8301 says rsa-sha1 "MUST NOT be used," and verifiers "MUST NOT consider signatures using RSA keys of less than 1024 bits as valid." Signers should use 2048-bit keys.
  • An expired signature: if x= is set and has passed, verifiers MAY return PERMFAIL (signature expired).

A temporary DNS failure is different. RFC 6376 allows TEMPFAIL (key unavailable), which receivers report as temperror. A later retry may pass.

Why this matters for DMARC

DMARC (RFC 9989) counts a DKIM signature only if it verifies and its d= domain aligns with the From: domain. A failing signature contributes nothing, so the message relies on aligned SPF. That's fragile after forwarding, and RFC 9989 says domains at p=reject must not rely solely on SPF. A message can carry several signatures. If any one aligned signature verifies, DKIM's part of DMARC is satisfied, which is why a failing vendor signature next to a passing one is often harmless.

A troubleshooting order that works

  1. Get the full header from a failing message and note header.d, header.s, and whether other signatures passed.
  2. Look up the selector in DNS. Is it there, complete (not truncated), not revoked, and 1024 bits or longer (preferably 2048)?
  3. Compare it with the key the sending platform shows as active.
  4. Send a fresh test directly to a mailbox you control. If it passes there but fails through a gateway, list or forwarder, the problem is in transit, not in DNS.
  5. If the sender supports it, set c=relaxed/relaxed.

Check the client's DKIM keys now

Run the free DKIM checker →

It probes common selectors plus one you type, follows CNAMEs, reports the RSA key length, and flags revoked keys (empty p=). A selector it can't find shows as Unknown, not as a failure.

Founding Partner: $1,999, one time. Watch DKIM keys across 50 client domains and get alerted when a selector changes or disappears. 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 "DKIM signature did not verify" mean?
The verifier checked the b= signature against the signed headers using the public key from DNS, and it didn't match. Under RFC 6376 that's PERMFAIL (signature did not verify).
How is it different from "body hash did not verify"?
A body hash failure means the message body changed or was hashed differently. "Signature did not verify" means the body check passed, but the header-and-key check failed.
Can a wrong DNS key cause DKIM to fail?
Yes. If the published key at the selector isn't the key the platform signs with, or it was truncated when it was split into 255-character strings, every signature fails.
Does an email gateway break DKIM?
It can, if it changes signed headers (for example by tagging the Subject) or edits the body after the message was signed. Test with and without the gateway hop.
Is a 1024-bit DKIM key still OK?
RFC 8301 sets 1024 bits as the minimum verifiers must accept, and says signers SHOULD use 2048. Keys under 1024 bits must not be treated as valid.
Does one failed DKIM signature fail DMARC?
Not on its own. DMARC passes if any aligned signature verifies, or if aligned SPF passes. A failed vendor signature next to a passing aligned one doesn't matter.
DKIM Signature Did Not Verify: Causes and How to Fix It | Client Posture