How to Send Free Transactional Emails with worker-mailchannels via Cloudflare Workers

Tristan Trommer
3 min readJan 8, 2024

--

Cloudflare Wokers and MailChannels will be coming to an end on June 30th, 2024.

Are you in search of a cost-effective, hassle-free solution for dispatching transactional emails? worker-mailchannels paired with Cloudflare Workers offers a streamlined process to accomplish just that. This guide will walk you through setting up and utilizing worker-mailchannels, ensuring a smooth experience in sending emails directly from your applications using an API.

Understanding Cloudflare Workers

Cloudflare Workers function as a serverless execution environment, empowering developers to execute code right at the network’s edge. This innovative feature, accessible through the Cloudflare ecosystem, eliminates the necessity of server management while offering global execution close to users, slashing latency and significantly improving performance.

Understanding MailChannels?

MailChannels serves as an outbound email relay service crafted to bolster email delivery and shield your domain’s reputation. It cleverly navigates outbound emails through a delivery-optimized network, resolving common email delivery hurdles like spam filters and IP reputation issues.

Understanding worker-mailchannels?

worker-mailchannels is a basic, API-driven application that eases the configuration of email delivery through Cloudflare Workers, leveraging MailChannels in the process.

Prerequisites

  1. A domain verified with Cloudflare.
  2. Wrangler CLI installed and authenticated on your system.

Deploy worker-mailchannels

  1. Clone the repository using git clone https://git.tristantrommer.com/tristantrommer/worker-mailchannels.git and navigate into the directory with cd worker-mailchannels.
  2. Install the required package dependencies with npm install.
  3. Deploy worker-mailchannels to Cloudflare with npm run deploy.
  4. Set up your Basic Auth username with npx wrangler secret put BASIC_AUTH_USERNAME and repeat the process for the password with npx wrangler secret put BASIC_AUTH_PASSWORD.

Setup Domain Lockdown

Create a TXT record with your domain to activate Domain Lockdown, crucial for using MailChannels through Cloudflare Workers.

  • Name: _mailchannels
  • Value: v=mc1 cfid=example.workers.dev

Setup SPF

Create an SPF record to mark MailChannels as an authorized email sender for your domain, hence reducing the chances of your emails being flagged as spam.

  • Name: @
  • Value: v=spf1 include:relay.mailchannels.net -all

Setup DKIM

Generate and deploy a DKIM private key using OpenSSL to validate that the emails are indeed sent from your domain, ensuring that the message content remains unaltered during transmission.

  1. Run openssl genrsa 2048 | tee priv_key.pem | openssl rsa -outform der | openssl base64 -A > priv_key.txt to generate a DKIM private key.
  2. Run 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 to generate a DKIM public key.
  3. Run npx wrangler secret put DKIM_PRIVATE_KEY to deploy the base64 encoded DKIM private key.

Create a TXT record for DKIM to make the public key discoverable.

  • Name: mcdkim._domainkey
  • Value: Record from pub_key_record.txt

Usage

To utilize the API, send a POST request to https://worker-mailchannels.example.workers.dev/api, including the specified JSON payload in the body of the request. Remember to appropriately configure the Authorization header.

{
"to": [
{
"email": "mail@example.com",
"name": "Example"
}
],
"replyTo": {
"email": "mail@example.com",
"name": "Example"
},
"cc": [
{
"email": "mail@example.com",
"name": "Example"
}
],
"bcc": [
{
"email": "mail@example.com",
"name": "Example"
}
],
"from": {
"email": "mail@example.com",
"name": "Example"
},
"subject": "Example",
"text": "Example",
"html": "<h1>Example</h1>"
}

Usage in JavaScript

const workerMailChannels = async () => {
const workerMailChannelsURL = 'https://worker-mailchannels.example.workers.dev/api';
const workerMailChannelsUsername = 'example';
const workerMailChannelsPassword = 'example';
const response = await fetch(workerMailChannelsURL, {
method: 'POST',
body: JSON.stringify({
'to': [
{'email': 'mail@example.com', 'name': 'Example'}
],
'from': {'email': 'mail@example.com', 'name': 'Example'},
'subject': 'Example',
'html': '<h1>Example</h1>',
'text': 'Example'
}),
headers: {
'content-type': 'application/json',
'Authorization': 'Basic ' + Buffer.from(workerMailChannelsUsername + ':' + workerMailChannelsPassword).toString('base64')
}
});
if (response.ok) return true;
return false;
}

--

--

Tristan Trommer

Hello, I'm Tristan Trommer. I'm a Junior Software Engineer passionate about technology.