Skip to main content
If your mail server DKIM-signs messages but a receiving server reports dkim=fail even though your configuration hasn’t changed, the cause may be header oversigning: your server declared Message-ID as a signed header while it was absent, and MailChannels inserted one afterward — invalidating the signature.

What causes this

DKIM signatures include an h= tag that lists every header covered by the signature. Some mail servers — Exim in particular — include Message-ID in this list by default, even when the header is not present in the message at signing time. This practice is called oversigning: by declaring a header as “signed” while it is absent, the server ensures that any later attempt to inject that header will invalidate the signature, which protects against header injection attacks. The problem arises when a message genuinely has no Message-ID at the time of signing, and one is legitimately added downstream. Because Message-ID was declared in the h= tag, inserting it after signing invalidates the signature. Here is the sequence that triggers the failure:
  1. Your application sends a message to your mail server without a Message-ID header.
  2. Your mail server DKIM-signs the message. The signature’s h= tag includes Message-ID — oversigned, even though the header isn’t there yet.
  3. Your server relays the signed message to MailChannels.
  4. MailChannels detects the missing Message-ID and inserts one.
  5. The receiving server validates the DKIM signature. Because Message-ID is now present but wasn’t there when the signature was computed, the signature fails.
Adding a Message-ID to a message that has none is normal message-handling behavior, not tampering. Although Message-ID is syntactically optional under RFC 5322, the RFC says every message SHOULD have one. In practice, major receivers expect it: Google’s Email Sender Guidelines state “Make sure every message includes a valid Message-ID,” and Yahoo’s sender requirements require senders to comply with RFC 5321 and RFC 5322. Messages without a valid Message-ID are more likely to be rejected or treated as suspicious by receiving mail servers. Nothing was tampered with. The failure is a side effect of oversigning a header that was absent at the time of signing.

Will this affect email delivery?

A DKIM failure is not harmless, even when DMARC still passes through SPF alignment. DKIM is one of the authentication signals receivers use when deciding whether to accept, filter, or classify a message. A failed DKIM signature does not automatically require rejection — RFC 6376 notes that verifying MTAs may apply local policy to unverifiable mail — but receivers may still treat it as a negative signal. It also means the message is no longer authenticated through that DKIM signature, which matters if SPF is unavailable, unaligned, or breaks in the future. A failed DKIM signature is also worth fixing even if DMARC currently passes through SPF alignment. It leaves delivery dependent on SPF alignment and removes DKIM as a reliable authentication path. If SPF is missing, fails, or is not aligned, and no other aligned DKIM signature passes, this DKIM failure can cause DMARC to fail as well. Under p=quarantine or p=reject, receivers that consider the domain’s DMARC policy may be more likely to filter, quarantine, or reject the message as part of their local policy.

How to fix it

Configure your sending application or mail server to always include a Message-ID header before the message reaches the DKIM signing step. Once Message-ID is present at signing time, it is included in the signed content and no downstream insertion is needed. Most modern mail clients and application mail libraries generate Message-ID automatically. Check whether your application’s mail library has an option to generate the header, and ensure it is enabled. If you are sending through your own SMTP stack, add Message-ID generation before the message is handed to the MTA. The important detail is ordering: generate Message-ID before DKIM signing, not after it.

Option 2: Stop signing the absence of Message-ID

If you cannot control Message-ID generation at the application layer, adjust your DKIM signing configuration so the signer does not sign the absence of Message-ID. For Exim, check the dkim_sign_headers option in the transport block that handles MailChannels delivery (for example, mailchannels_smtp). Exim’s header list has three modes per entry: a bare name oversigns by default when the header is absent, a + prefix explicitly oversigns, and an = prefix signs only the header instances that are actually present — so a header added later, like a downstream Message-ID insertion, no longer breaks the signature. See the Exim DKIM documentation for the full dkim_sign_headers option reference. If your config lists Message-ID with no prefix or a + prefix, switching it to =Message-ID is the fix. If your Exim version does not support prefixes, remove Message-ID from the list entirely. See DKIM configuration for cPanel for how to edit the Exim transport configuration.
Using =Message-ID is the better compromise: it still signs an existing Message-ID, so changes to that signed header will break the signature, but it does not sign the absence of Message-ID. Removing Message-ID from the list entirely means the header is unprotected by that signature.

Confirm this is the cause

Check the following to verify this specific issue before making changes:
  1. Was Message-ID missing from the original message? Look at the raw message as sent from your server (before MailChannels received it). If no Message-ID header was present, that confirms one required condition for this failure.
  2. Does the DKIM signature sign the absence of Message-ID? Inspect the DKIM-Signature header in the delivered message. If Message-ID was missing before signing and message-id appears in the h= tag, the server signed the absence of that header.
  3. Does the Message-ID in the delivered message differ from your application’s normal format? If the value looks different from what your application normally generates, or uses infrastructure-specific formatting, it may have been inserted downstream. Confirm by checking outbound logs or the raw message before it reached MailChannels.
  4. Do SPF and DMARC pass alongside dkim=fail? If spf=pass and dmarc=pass appear alongside dkim=fail, the message may have been delivered because SPF alignment, or another aligned DKIM signature, satisfied DMARC. This pattern is consistent with the issue, but the decisive evidence is still: Message-ID was missing before signing, message-id appears in h=, and Message-ID is present after relay.
  5. Is this a header failure rather than a body hash failure? This issue affects the signed header set, not the message body. If the receiver reports a body hash mismatch, look for body modification after signing instead.