How to build a static blog part 14

Friday, 14 July 2023

The Cloudflare function

Lets create a new file, functions/mail.js

let destinationEmail = ''
let fromEmail = ''
let dkimDomain = ''
let dkimPrivateKey = ''
const headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'POST',
    'Access-Control-Allow-Headers': 'Content-Type',

export async function onRequestPost({ request, env }) {
    destinationEmail = env.DESTINATION_EMAIL
    fromEmail = env.FROM_EMAIL
    dkimPrivateKey = env.DKIM_PRIVATE_KEY
    dkimDomain = env.DKIM_DOMAIN
    return await handleRequest(request)

async function handleRequest(request) {
    const requestBody = await readRequestBody(request)
    if (requestBody === null) {
        return new Response('Bad request', { headers, status: 400 })
    const result = await sendEmail(requestBody)
    return result

async function readRequestBody(request) {
    const { headers: requestHeaders } = request
    const contentType = requestHeaders.get('content-type') || ''

    if (contentType.includes('text/plain')) {
        const data = await request.text()
        return JSON.parse(data)
    return null

async function sendEmail({ email, message, name, phone }) {
    if (!email || !name) {
        return new Response('Required info missing', { headers, status: 422 })
    const content = [
            type: 'text/plain',
            value: `
Hey there, message submitted on your website!

    Name: ${name}, 
    Email: ${email}, 
    Phone: ${phone}, 
    Message: ${message}
    const mailServerResponse = await fetch(
        new Request('', {
            method: 'POST',
            headers: {
                'content-type': 'application/json',
            body: JSON.stringify({
                personalizations: [
                        to: [{ email: destinationEmail, name: 'Phil' }],
                        reply_to: { email },
                        dkim_domain: dkimDomain,
                        dkim_selector: 'mailchannels',
                        dkim_private_key: dkimPrivateKey,
                from: {
                    email: fromEmail,
                subject: 'Contact form submission!',
    const result = `From Mailserver: ${mailServerResponse.status} ${mailServerResponse.statusText}`
    return new Response(result, { headers, status: mailServerResponse.status })

This is the code for a Cloudflare function. Notice there are a lot of environment variables for sending email safely via the Mailchannels api. We need to set those up in Cloudflare.

One thing to be aware of here is that Mailchannels is very good at detecting and blocking spam. This means that you won't be getting spammed by your own website, but also that you should not be tempted to use this technology for sending spam, they will block/throttle you. No, I know you wouldn't send spam, nor would I but people do.

So simply follow the instructions here to set up DKIM (DomainKeys Identified Mail) credentials for your domain, and add them as environment variables for your Pages project. You also need to add the to and from email addresses, so the full list of Production environment variables will be as below:

Variable               Value
DESTINATION_EMAIL      your email address!
DKIM_DOMAIN            your domain ( or whatever)
DKIM_PRIVATE_KEY       ierhfieurh... etc the private key you generated
FROM_EMAIL             [email protected] or whatever
NODE_VERSION           18

You should also add the NODE_VERSION variable to your Preview environment, too.

Save, commit and push the function code to your Git remote repo. That will then be automatically deployed. Deployments usually take 2 or three minutes to build and upload.

That's it. With luck you can now test your contact form and see your test messages in your inbox.

I hope this has been instructive, and I apologise if any of this didn't work, or if I missed some vital piece! If so please open an issue on the Github repo here, and I'll get on it.

go back