DKIM Fail: Every DKIM Error Explained and How to Fix It

Seeing dkim=fail, permerror, temperror, or body hash did not verify? This guide explains every DKIM result you will find in email headers, what causes each one, and the exact fix.

DKIM (DomainKeys Identified Mail) adds a cryptographic signature to your outgoing mail. The receiving server fetches your public key from DNS, recomputes the signature, and compares. When the two do not match, or the key cannot be found, the receiver records a DKIM failure in the message headers and your mail loses one of the two authentication signals that DMARC depends on.

The good news is that a DKIM failure always tells you why it failed. The reason is written into the header. This guide shows you how to read it, what each result means, and how to fix every common cause.

Start with the header: a worked example

Here is the Authentication-Results header from a real-world style failure, as Gmail would record it. Open any message in Gmail, choose "Show original", and you will find a block like this near the top.

Authentication-Results: mx.google.com;
       dkim=fail (body hash did not verify) [email protected] header.s=s1 header.b=K3pQ9x2f;
       spf=pass (google.com: domain of [email protected] designates 198.51.100.24 as permitted sender) [email protected];
       dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=example.com

Three pieces of that line answer most questions before you touch DNS:

  • header.s=s1 is the selector. The receiver looked for your public key at s1._domainkey.example.com.
  • [email protected] is the signing domain. It must align with the From domain for DMARC to pass on DKIM.
  • The reason in parentheses, here body hash did not verify, names the failure family. The fixes below are organised by that reason.

Further down the same message you will find the signature itself:

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=s1;
        h=from:to:subject:date:message-id:mime-version:content-type;
        bh=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN/XKdLCPjaYaY=;
        b=K3pQ9x2fVb1n4Qm9...
  • d= and s= are the domain and selector the signer used. If they do not match the header.i and header.s values above, you are looking at a different signature (some messages carry several).
  • h= lists the headers that were signed. If any of these changed after signing, the signature fails.
  • bh= is the hash of the message body as it was when signed. A body hash did not verify failure means the body no longer produces this hash.
  • b= is the signature over the headers and the body hash.

In the example, SPF passed but DKIM failed on the body hash and DMARC failed because the SPF domain ([email protected]) is the same organisational domain, so alignment should have rescued it. That combination usually means the message went through a mailing list or a gateway that rewrote the body. Keep reading for the fix.

The six DKIM results

ResultMeaningSeverity
`pass`Signature verified and key foundNone, working correctly
`fail`Signature present but verification failedHigh, needs fixing
`permerror`Permanent configuration error (key, selector, or syntax)High, needs fixing
`temperror`Temporary error, usually a DNS timeoutMedium, often self-resolves
`none`No DKIM signature on the messageMedium, you should be signing
`neutral` / `policy`Signature present but the receiver would not use it (weak key, unsupported algorithm)Medium, regenerate the key

What each failure means and how to fix it

dkim=fail (signature verification failed)

The receiver found your public key but the signature did not check out against it.

Causes:

  • The private key used for signing does not match the public key in DNS. This is the classic symptom of a key rotation where DNS was never updated, or the wrong key was pasted into DNS.
  • One of the headers listed in the h= tag was modified after signing. Gateways that rewrite the Subject line (adding "[EXTERNAL]", for example) do this.
  • The signature was created with an old key that has since been removed from DNS.

Fix: Regenerate the key pair in your sending service and republish the public key. If you rotate keys, keep the old public key in DNS for at least a week so mail already in transit still verifies. If a gateway is rewriting headers, sign after the gateway or stop it modifying signed headers.

dkim=fail (body hash did not verify)

The headers were fine but the body changed after it was signed.

Causes:

  • A mailing list, forwarder, or security gateway added a footer, disclaimer, tracking pixel, or warning banner.
  • Line endings were converted between LF and CRLF somewhere in the pipeline.
  • Character encoding changed, or an attachment was rescanned and re-encoded.

Fix: For systems you control, make DKIM signing the last step before the message leaves. Move disclaimer and footer insertion before signing, and check for content-altering security appliances. For mail that legitimately passes through lists and forwarders, this failure is expected. DMARC will still pass if SPF passes and aligns, and receivers increasingly honour ARC (Authenticated Received Chain) for forwarded mail. See why email forwarding breaks authentication.

dkim=permerror

A permanent problem with the configuration itself. The receiver could not even attempt verification. The reason in parentheses tells you which of these you have:

  • no key for signature: nothing exists at selector._domainkey.yourdomain. Either the record was never published or the selector in the signature does not match the DNS name.
  • key syntax error or invalid tag-value syntax: the record exists but is malformed. Look for a missing v=DKIM1, a truncated p= value, stray whitespace, or line breaks introduced when the key was pasted.
  • selector not found: the s= tag references a selector your DNS does not have. Common when a service changes its default selector or when Microsoft 365 alternates between selector1 and selector2.

Fix: Query the exact name the receiver used and compare it with what your sending service expects. The four-step diagnosis below does this.

dkim=temperror

A temporary failure, almost always DNS.

  • DNS lookup timed out: the receiver could not reach your nameservers in time.
  • DNS server error: your DNS provider returned an error.

These are not directly fixable from the sender side, and most clear on retry. If they persist, look at your DNS hosting. Slow or flaky authoritative nameservers cause temperrors for every receiver at once, which turns a DNS problem into a deliverability problem. Reliable DNS hosting, sensible TTLs, and DNS monitoring are the answer.

dkim=none

The message was not signed at all.

Causes: DKIM is not enabled in the sending service, signing is disabled for a particular message type, or a self-hosted mail server was never configured to sign.

Fix: In Google Workspace or Microsoft 365, enable DKIM signing in the admin console for the sending domain. In an ESP such as SendGrid or Mailchimp, complete domain authentication so the service signs with your domain instead of its own. On a self-hosted server, install and configure OpenDKIM or equivalent and check the mail log for signing errors.

Weak key, unsupported algorithm, or expired signature

Three less common results that look like failures:

  • key too small or dkim=policy (weak key): a 512-bit or 768-bit key. Receivers reject these. Generate a 2048-bit key. See DKIM key length.
  • unsupported algorithm: an old signing algorithm such as rsa-sha1. Use rsa-sha256, or ed25519 where your service supports it.
  • signature expired: the signature carries an x= expiry tag that has passed. Remove the tag or extend it. Expiry tags are rarely useful on transactional mail.

The eight configuration mistakes behind most failures

Most DKIM failures come down to one of these.

1. No DKIM record published

The service signs, but you never added the public key to DNS. Every service that sends as your domain needs its own record.

2. Wrong selector

The selector in the signature must match the DNS name exactly.

ServiceDefault selectorDNS record location
Google Workspace`google``google._domainkey.yourdomain.com`
Microsoft 365`selector1`, `selector2``selector1._domainkey.yourdomain.com`
SendGrid`s1`, `s2``s1._domainkey.yourdomain.com`
Mailchimp`k1`, `k2`, `k3``k1._domainkey.yourdomain.com`
Amazon SESThree random tokens`token._domainkey.yourdomain.com`

Multiple records do not conflict. Each service uses its own selector, so a domain that sends through Google Workspace and SendGrid simply has both records.

3. Key mismatch after rotation

Keys were rotated in the service but DNS still holds the old public key, or the wrong key was copied. See the rotation procedure below.

4. Message modified in transit

Mailing lists, auto-forwarders, corporate gateways, and antivirus scanners all rewrite mail. This is the usual cause of body hash failures on mail that verified fine when it left you.

5. DNS propagation

After adding or changing a record, some resolvers still serve the old answer until the TTL expires. Allow up to 48 hours, and lower the TTL before planned changes.

6. Record syntax errors

The public key is long and easy to truncate. Compare the p= value in DNS character by character with the one your service shows you.

# Broken (truncated)
v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC...

# Correct (complete key)
v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCsR8rRwZ...complete...key==

Some DNS providers split long TXT records into 255-character chunks automatically. Others require you to do it. Either is fine as long as the chunks concatenate to the full key.

7. Key too short

Anything under 1024 bits fails at major receivers. Use 2048 bits.

8. CNAME published as TXT, or the reverse

SendGrid, Mailchimp, and Amazon SES give you CNAME records that point at keys they host. Google and Microsoft give you TXT records. Publishing the wrong type produces no key for signature.

s1._domainkey.yourdomain.com  CNAME  s1.domainkey.u12345.wl.sendgrid.net

Diagnose it in four steps

1

Read the selector and domain from the failing message

In the DKIM-Signature header, note s= and d=. In the example above, s=s1 and d=example.com.

2

Query DNS for the key the receiver looked up

Run dig +short TXT s1._domainkey.example.com. No answer means no record (or wrong selector). An answer that does not start with v=DKIM1 means a syntax problem.

3

Compare the key with your sending service

Open the DKIM settings in the service that sent the message and compare the p= value it shows with what DNS returned. Any difference is a key mismatch.

4

Check the reason in Authentication-Results

If DNS and the key are correct and the reason is body hash did not verify, the message was altered after signing. Look at the path the message took, not at DNS.

DKIM Test runs steps two and three for you: enter the domain and selector and it fetches the record, validates the syntax, and reports the key length.

Fix it step by step

  1. Identify the signing service. Corporate mail (Google, Microsoft), a marketing platform, or a transactional service. The failing selector tells you which.
  2. Get the DKIM record from that service. Generate keys if none exist, then copy the record exactly as shown, including the record type.
  3. Publish it in DNS. Correct type, correct selector, complete key.
  4. Enable signing. Some services require an explicit toggle after the record verifies.
  5. Send a test and read the header. You want dkim=pass with the selector you expect and header.i matching your From domain.

Rotating keys without breaking DKIM

Key rotation is where most avoidable failures come from. The safe order is:

  1. Generate a new key pair in the sending service, on a new selector.
  2. Publish the new public key in DNS.
  3. Wait for propagation, 24 to 48 hours.
  4. Switch signing to the new selector.
  5. Leave the old public key in DNS for at least seven days, then remove it.

Services that rotate keys automatically (Microsoft 365 alternates between selector1 and selector2, and Amazon SES rotates its tokens) rely on the CNAME records you published pointing at keys they control. If you replaced those CNAMEs with static TXT records, automatic rotation will break signing.

Testing after changes

1

Confirm the DNS record

dig +short TXT selector._domainkey.yourdomain.com from at least two networks, since propagation is uneven.

2

Send a real message

Send through the production service to a Gmail, Outlook.com, and Yahoo mailbox you control.

3

Read Authentication-Results

Look for dkim=pass and check that header.s is the selector you just changed.

4

Watch DMARC reports for a week

Aggregate reports will show any sending source that is still failing DKIM. See DMARC aggregate reports explained.

Debugging checklist

Header saysCheckFix
permerror (no key for signature)Does the record exist at selector._domainkey?Publish the key, or correct the selector
permerror (key syntax error)Does it start with v=DKIM1 and have a complete p=?Re-paste the record from the service
fail (signature verification failed)Does the DNS key match the service's key?Regenerate and republish; keep old key during rotation
fail (body hash did not verify)Did anything rewrite the body after signing?Sign last; accept it for forwarded mail and rely on SPF alignment or ARC
noneIs DKIM enabled for this domain in this service?Enable signing and complete domain authentication
temperrorAre your nameservers slow or down?Fix DNS hosting; retry
policy (weak key)Is the key under 1024 bits?Generate a 2048-bit key

DKIM failures look cryptic but they are almost always a DNS record, a key mismatch, or a message modified in transit. Read the reason in the header first, and it points you straight at the fix.


Monitor DKIM Automatically

The Email Deliverability Suite monitors your DKIM records, SPF, DMARC, MX records and blacklist status daily. Get alerts when DKIM configuration breaks, before your emails start failing.

Catch DKIM issues early

SPF, DKIM, DMARC, MX, and blacklist monitoring for unlimited domains. $39/month.