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'));