Skip to main content

DKIM

TXT recordRFC 6376

DomainKeys Identified Mail

DKIM (DomainKeys Identified Mail, RFC 6376) adds a cryptographic signature to outgoing email. The sending server signs selected headers and the message body with a private RSA or Ed25519 key. The public key is published in a DNS TXT record at selector._domainkey.domain. Receiving servers verify the signature. DKIM proves the message was sent by a server holding the private key and that the signed headers and body were not modified in transit.

How it works

The sending server computes a SHA-256 hash of the canonicalized message body (bh=). It then constructs a canonicalized header string including selected headers plus the DKIM-Signature header itself (with b= empty). It signs the combined hash with the private key to produce the signature (b=). The receiving server reads the DKIM-Signature header, retrieves the public key from DNS at {s}._domainkey.{d}, and verifies the signature. If verification passes, the message was sent by the key owner and the signed content was not modified.

Details

DKIM provides message integrity and sender authentication via cryptographic signatures.

Key concepts: Selector: a label (e.g., google, s1, 2024) that identifies which key pair was used. Multiple selectors allow key rotation without downtime. d= tag: the signing domain. Must match or align with the From header for DMARC alignment. s= tag: the selector. The DNS lookup is: {selector}._domainkey.{d=domain} TXT h= tag: list of headers included in the signature. At minimum: From, To, Subject, Date. bh= tag: base64-encoded SHA-256 hash of the canonicalized body. b= tag: base64-encoded signature over the canonicalized headers and body hash.

Signing algorithms: rsa-sha256: RSA with SHA-256. Minimum 1024-bit key (2048-bit strongly recommended). ed25519-sha256: Ed25519 with SHA-256. Smaller keys, faster verification, more modern. RFC 8463.

Canonicalization: relaxed/relaxed (common): headers and body are normalized before signing. Converts multiple whitespace to one space, removes trailing whitespace. More forgiving of minor modifications by mail servers in transit. simple/simple: strict -- any whitespace change breaks the signature.

DKIM and forwarding: Unlike SPF, DKIM survives forwarding as long as the message content and signed headers are not modified. Most forwarders do not modify headers. Mailing list software that adds footers or Subject prefixes [list] breaks DKIM body or header signatures.

Key rotation: Add a new selector with the new key pair. Update signing to use the new selector. Retire the old selector after TTL expires. Because the selector is in the signature header, old messages signed with the old selector remain verifiable until the old DNS record is removed.

DNS record example

TXT record syntax
; DKIM public key record
; Format: {selector}._domainkey.{domain}
google._domainkey.example.com.  IN TXT (
  "v=DKIM1;"
  "k=rsa;"
  "p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC..."
)

; v=DKIM1  – DKIM version
; k=rsa    – key type (rsa or ed25519)
; p=       – base64-encoded DER public key
; If p= is empty: key has been revoked

; DKIM-Signature header added to outgoing message:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
  d=example.com; s=google;
  h=from:to:subject:date:message-id;
  bh=47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=;
  b=rHIb3FzEm4kP...

On failure

A failed DKIM signature (verification error) causes the message to fail DKIM. The receiving server records the result in an Authentication-Results header. DMARC then determines the enforcement action based on the DMARC policy (p=none/quarantine/reject). A missing DKIM signature is treated the same as a failed signature for DMARC purposes.

Limitations

  • !Mailing lists that modify Subject: ([List] prefix) or add footers break DKIM body hash
  • !Does not prevent email forwarding abuse if From header is spoofed
  • !Key management overhead: rotation requires DNS updates + TTL wait
  • !RSA keys under 1024 bits are rejected; 2048+ recommended; DNS TXT records have 512-character limits per string, requiring multi-string records for large keys

See Also