A DKIM signature is a promise that the signed parts of the message have not changed since the sender's server signed them, checked with a public key the receiver fetches from DNS. dkim=fail means that check did not work out. The words after it in Authentication-Results say which part failed, and each points somewhere different.
Authentication-Results: mx.example.net;
dkim=fail (body hash did not verify) header.d=example.com header.s=s1
header.d is the signing domain and header.s the selector. Keep both; every fix below starts from them.
"body hash did not verify"
The receiver hashed the body it got and the result does not match the hash in the signature, the bh= tag. Verifiers compare that hash before they check the signature itself, so this result says nothing about the key yet. The body changed after signing.
Something between your signing server and the receiver touched the message:
- a mailing list or a forwarder added a footer or an unsubscribe line;
- a security gateway rewrote links for click protection, or a disclaimer rule appended text after another system had already signed the message, a CRM signing and Microsoft 365 relaying for instance;
- a relay re-encoded the body, changing line endings or the transfer encoding.
When the change happens inside your own setup, move the signing to after it: the disclaimer or footer rule first, DKIM last. When it happens at someone else's forwarder or mailing list, nothing on your side repairs that copy. Sign everything and leave the body alone after signing; whether the receiver then trusts the forwarder's ARC seal and lets the message through is its decision.
"signature did not verify"
The body may be intact, but the signature over the headers does not check out with the key in DNS. Either a signed header changed in transit, a subject tag added by a mailing list for example, or the key in DNS is not the one the server signs with. Check the second first: a key rotated on the sending side without publishing the new public key, or a TXT record split badly across strings so the key in DNS is damaged.
Look the selector up in the DKIM checker. If the key there is not the one your provider shows in its settings, republish it.
"no key for signature"
The receiver asked DNS for selector._domainkey.example.com and got nothing. The record was never published, was deleted, or was published under a different selector or with the domain doubled by a panel that appends it to the name (s1._domainkey.example.com.example.com). The DKIM checker shows what DNS returns for the selector from the header.
dkim=pass, and DMARC still fails
A signature can pass for the wrong domain. Newsletter platforms and CRMs sign with their own domain until you set up DKIM for yours, and then header.d is sendgrid.net or mcsv.net, not you. That passes DKIM and does nothing for DMARC; see DMARC fail.
Keys that are too weak
RFC 8301 tells verifiers not to accept signatures made with RSA keys shorter than 1024 bits, so such a message counts as unsigned. 2048 bits is what the same RFC recommends; move to it the next time you rotate.
How the test reports it
Every DKIM signature in the test message gets its own line in the DKIM check, with the d= domain, the selector and whether it verified. A footer added by your own outbound rule shows up there after a single send, as a signature that fails where it should pass.