DKIM (DomainKeys Identified Mail) is a sender authentication method. It uses asymmetric cryptography (public-key cryptography).

Encryption vs Hashing

  • Encryption means the the encryted data can be decrypted
  • Hashing means the hashed data can practically NOT be restored (one-way function)

How DKIM it works

  • The sending mail server hashes the the e-mail body (bh=).
  • The sending mail server hashes the e-mails body and headers and appends it to the e-mail header (b=).
  • The sending mail server adds the DKIM-Signature (including bh= and b=) to the message headers.
  • Sending the email message
  • The receiving mail server fetches the public-key that is defined as a TXT record in the DNS-zone of the sender email address domain. The sender email address is the From-Header value.
  • The receiving mail server uses the public-key to validate the signature (DKIM-Signature).

Setup DomainKeys / DKIM

In order to get DKIM work, we have to enable it on our mail server (e.g. mailenable)
OR use a relay service (like SendGrid or SocketLabs) that supports DKIM out of the box.

TXT Record

Copy the generated DKIM text (v=DKIM1; p=...) into the DNS TXT record created for the selector you specified OR got from your relay service.

If you are using a relay service you just have to set a CNAME record instead.
So you do NOT have to create a TXT record yourself.

TXT {selector}._domainkey.example.com
v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTWG+MmMnbvTeCxbX11SzzgOFAC/nFARxb7vnqtAL6XNi3yFinPYKD/mnRzSSSv0mCcsf6FJXcBkewgBQDuoaVyA5ky5NYyLQYGiU5DM+gvgdZ7TLgCKTpIv0oxbWcLhw5H/epMeapjZfDy83HlHG5SiYk/WLDYmMMUXtLR6+pEwIDAQAB;

p= is the public-key parameter.

DKIM-Signature

When your mail server has enabled DKIM it should automatically add the following DKIM-Signature header.

DKIM-Signature: v=1; c=relaxed/relaxed; h=from:date:subject:message-id:reply-to:to:mime-version:content-type;
  d=example.com; s=dkim; a=rsa-sha256;
  bh=+v3B2soRaILbyKrYhoq9RrmiAPiiBp6bxP02icRUtLM=;
  b=pqaNvlyrwEq3EsNff9j4Dp/HpeScd1/95uW1/DXmIPzcurwGwKYLgbzy/KCD3MvCl
  ETiFRZTuIryCVUtsikQQ2l2svf4ASDjpK8QwjKUYU/0tDdptNebFd9cG8dFK2zQlstX
  XPTJR6TSIktlUIwDgaZL8zdotDRKQuz94KwYccE=;
  • v= is the version
  • a= is the signing algorithm
  • c= is the canonicalization algorithm (aka standardization or normalization)
    converts data into a "standard", "normal" or "canonical" form.
  • d= is the domain
  • s= is the selector
  • h= defines the headers to include into the hash
  • bh= is the body hash
  • b= is the hash of the header fields listed in the h= parameter and body hash (bh=)

The receiving mail server now knows how to locate the public key:
[s=] + "._domainkey." + [d=] => dkim._domainkey.example.com

Difference between SPF vs DKIM

  • SPF authenticates the RFC5321.MailFrom address (Sender-Header "Envelope")
  • DKIM authenticates the RFC5322.From address (From-Header "Letter")

Verification of the signature

For programmers to understand how the verification of the signature works, this Node.js code will verify the signature.

const signature = 'pqaNvlyrwEq3EsNff9j4D....................'; // b=
const headers = 'mime-version:1.0\r\nfrom:"mail@example.com" <sender@example.com>\r\nto:receiver@example2.com\r\n....................\r\ndkim-signature:v=1; c=relaxed/relaxed; h=mime-version:from:to:reply-to:date:subject:content-type:content-transfer-encoding:message-id; d=example.com; s=dkim; a=rsa-sha256; bh=+v3B2soRaILbyKrYhoq9RrmiAPiiBp6bxP02icRUtLM=; b=;';
const publicKey = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTWG+Mm....................';
const normalizedPublicKey = `-----BEGIN PUBLIC KEY-----\n${Buffer.from(publicKey.toString('base64'))}\n-----END PUBLIC KEY-----`;

const isSignatureValid = crypto.createVerify('rsa-sha256')
  .update(headers)
  .verify(normalizedPublicKey, Buffer.from(signature, 'base64'));

Check your DKIM txt record