← RFC Reference

DKIM — DomainKeys Identified Mail

Internet Standard Email Authentication AuthenticationCryptography
ELI5: Think of DKIM as a tamper-evident wax seal on a letter. Before sending, the mail server stamps the message with a unique seal (a cryptographic signature). When it arrives, the recipient can check the seal against a public key published in DNS. If the seal is intact, the message hasn’t been altered in transit and really came from someone with access to that domain’s private key.

Why This RFC Exists

SPF verifies that a message came from an authorized IP address, but it says nothing about the message content. A message could pass SPF, then be modified by a compromised relay. SPF also breaks when mail is forwarded, because the sending IP changes.

DKIM solves both problems. By attaching a cryptographic signature to the message itself, it provides a domain-level identity assertion that survives forwarding (the signature travels with the message) and guarantees content integrity (any modification invalidates the signature).

RFC 6376, published in 2011, is the current DKIM specification. It obsoleted RFC 4871 and introduced improvements to canonicalization, key management, and signature semantics. It remains the foundation of modern email authentication alongside SPF and DMARC.

How It Works

Signing (Sender Side)

  1. The sending mail server (or a signing agent upstream) selects which headers and the body to sign.
  2. It canonicalizes the selected content using either simple or relaxed algorithms to normalize whitespace and casing.
  3. It computes a hash of the canonicalized body, then a hash of the selected headers plus the body hash.
  4. It signs the header hash using the domain's private key (RSA or Ed25519).
  5. It adds a DKIM-Signature header to the message containing the signature, the signing domain (d=), the selector (s=), and metadata about what was signed.

Verification (Receiver Side)

  1. The receiver extracts the d= (domain) and s= (selector) values from the DKIM-Signature header.
  2. It queries DNS for the public key at <selector>._domainkey.<domain>.
  3. It re-canonicalizes the signed headers and body using the same algorithm specified in the signature.
  4. It verifies the signature against the public key. If valid, the result is pass.

Example DKIM-Signature Header

DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=mtg20240101; h=from:to:subject:date:message-id:mime-version:content-type; bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=; b=LjIEJLNOTAREALSIGh8gAiGVQOr3K7...truncated...

DNS Public Key Record

mtg20240101._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEB...truncated..."

Key Technical Details

Canonicalization

Email can be subtly modified in transit (trailing whitespace stripped, headers re-folded). Canonicalization normalizes the content before hashing so that benign changes don't break the signature. Two algorithms are available, specified separately for headers and body:

Algorithm Headers Body
simple No changes except trailing whitespace on the header value No changes except trailing empty lines
relaxed Lowercases header names, unfolds lines, compresses whitespace Compresses whitespace, removes trailing whitespace per line

The most common setting is c=relaxed/relaxed, which tolerates the most common in-transit modifications.

Key Types

RFC 6376 defined RSA signatures. RFC 8463 later added Ed25519 support. RSA keys should be at least 2048 bits; 1024-bit keys are considered weak and are rejected by some receivers. Ed25519 keys are much smaller (44 characters in DNS) and faster to verify.

Selectors

The selector (s= tag) lets a domain publish multiple DKIM keys simultaneously. This is essential for key rotation: publish a new key under a new selector, start signing with it, then remove the old selector's DNS record after a transition period.

The l= Tag (Body Length Limit)

The optional l= tag limits how many bytes of the body are signed. This was intended to allow mailing lists to append footers without breaking signatures. In practice, it creates a security vulnerability: an attacker can append malicious content after the signed portion. Most security-conscious implementations avoid using l=.

Header Signing

The h= tag lists which headers are included in the signature. Best practice is to sign at least: From, To, Subject, Date, Message-ID, MIME-Version, and Content-Type. The From header is required by specification. Signing a header that doesn't exist prevents it from being added after signing (an important anti-replay measure).

Common Mistakes

Deliverability Impact

Related RFCs