DomainKeys Identified Mail (DKIM) is an email authentication standard that allows you to sign email messages from your domain with a digital signature using public-key cryptography. By adding a DKIM signature to messages sent through the MailChannels Send API, you can prevent others from spoofing your domain, if used in combination with a sufficiently strong Domain-based Message Authentication, Reporting & Conformance (DMARC) policy.
To add a DKIM signature to a message, add the following fields to the personalization
object for the message:
dkim_domain
: This is the domain (d=
) field for the DKIM signature. To pass DMARC, this should be aligned with the domain in theFrom
header address.dkim_selector
: This is the selector (s=
) field for the DKIM signature. It specifies where to find the associated public key in the DNS - see the DKIM specification for more details.dkim_private_key
: The base-64 encoded private key.
See below for a full example of sending a message from a Cloudflare Worker with a DKIM signature:
addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
let send_request = new Request("https://api.mailchannels.net/tx/v1/send", {
"method": "POST",
"headers": {
"content-type": "application/json",
},
"body": JSON.stringify({
"personalizations": [{
"to": [ {"email": "test@example.com",
"name": "Test Recipient"}],
"dkim_domain": "example.com",
"dkim_selector": "mcdkim",
"dkim_private_key": "<base64 encoded private key>"
}],
"from": {
"email": "sender@example.com",
"name": "Test Sender",
},
"subject": "Test Subject",
"content": [{
"type": "text/plain",
"value": "Test message content\n\n" + content,
}],
}),
});
let respContent = "";
// only send the mail on "POST", to avoid spiders, etc.
if( request.method == "POST" ) {
const resp = await fetch(send_request);
const respText = await resp.text();
respContent = resp.status + " " + resp.statusText + "\n\n" + respText;
}
let htmlContent = "<html><head></head><body><pre>" +
"</pre><p>Click to send message: <form method="post"><input type="submit" value="Send"/></form></p>" +
"<pre>" + respContent + "</pre>" +
"</body></html>";
return new Response(htmlContent, {
headers: { "content-type": "text/html" },
})
}
Reference documentation is available at https://api.mailchannels.net/tx/v1/documentation
Cloudflare has some documentation on creating a DKIM record here: https://www.cloudflare.com/en-ca/learning/dns/dns-records/dns-dkim-record/.
This fantastic "Creating a DKIM private and public key" guide provided with permission from: https://github.com/cloudsecurityalliance/webfinger.io/blob/main/docs.webfinger.io/DKIM-setup.md
Creating a DKIM private and public key:
Private key as PEM file and base64 encoded txt file:
openssl genrsa 2048 | tee priv_key.pem | openssl rsa -outform der | openssl base64 -A > priv_key.txt
Public key as DNS record:
echo -n "v=DKIM1;p=" > pub_key_record.txt && \
openssl rsa -in priv_key.pem -pubout -outform der | openssl base64 -A >> pub_key_record.txt
Creating the public DNS records:
Then set a DNS TXT record of selectorname._domainkey.example.org with the value from pub_key_record.txt, e.g.:
mailchannels._domainkey IN TXT "v=DKIM1; p=<content of the file pub_key_record.txt>"
Now you need a DMARC record to enforce usage of the DKIM signature:
_dmarc IN TXT "v=DMARC1; p=reject; adkim=s; aspf=s; rua=mailto:YYY; ruf=mailto:YYY pct=100; fo=1;"
Setting up your Javascript to use it:
In your cloudflare worker simply add something like:
"personalizations": [
{ "to":
[
{
"email": data["to_email"]
}
],
"dkim_domain": data["DKIM_DOMAIN"],
"dkim_selector": data["DKIM_SELECTOR"],
"dkim_private_key": data["DKIM_PRIVATE_KEY"]
}
],
where the data dict is setup e.g.:
email_data["DKIM_DOMAIN"] = DKIM_DOMAIN;
email_data["DKIM_SELECTOR"] = DKIM_SELECTOR;
email_data["DKIM_PRIVATE_KEY"] = DKIM_PRIVATE_KEY;
Which in turn gets the data from environmental variables, either set in the web UI for Cloudflare workers, or in wrangler.toml for example:
[env.production.vars]
DKIM_DOMAIN = "main domain"
DKIM_SELECTOR = "selectorname"
DKIM_PRIVATE_KEY = "priv_key.txt material goes here"
And you should be good to go.
--
There are also various services that can help you create a DKIM key pair if needed.
Here are a few:
Could you help me. I have followed all the steps correctly. But it is responding with error message:
{ "errors": ["bad request - DKIM public key and private key mismatch: fail to parse public key in PKIX format"] }