Help Center

Adding a DKIM Signature

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 the From 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:

Was this article helpful?
0 out of 0 found this helpful
Have more questions? Submit a request

Comments

  • Avatar
    Deo Kumar

    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"] }

    Edited by Deo Kumar
    Comment actions Permalink

Article is closed for comments.