How to Send Free Transactional Emails with worker-mailchannels via Cloudflare Workers
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
- A domain verified with Cloudflare.
- Wrangler CLI installed and authenticated on your system.
Deploy worker-mailchannels
- Clone the repository using
git clone https://git.tristantrommer.com/tristantrommer/worker-mailchannels.git
and navigate into the directory withcd worker-mailchannels
. - Install the required package dependencies with
npm install
. - Deploy worker-mailchannels to Cloudflare with
npm run deploy
. - Set up your Basic Auth username with
npx wrangler secret put BASIC_AUTH_USERNAME
and repeat the process for the password withnpx 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.
- Run
openssl genrsa 2048 | tee priv_key.pem | openssl rsa -outform der | openssl base64 -A > priv_key.txt
to generate a DKIM private key. - 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. - 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;
}