Skip to content

Email from Cloudflare Workers

Send with one fetch to the Mektup API, since Workers have no built-in SMTP client, and receive by pointing a Mektup mailbox webhook at your Worker. The signature check runs on Web Crypto, no Node APIs needed.

Updated

A Worker that sends and receives

src/index.js
export default {
  async fetch(request, env) {
    const url = new URL(request.url);

    // Send: POST /send { to, subject, text }
    if (url.pathname === "/send") {
      const { to, subject, text } = await request.json();
      return fetch("https://api.usemektup.com/v1/emails", {
        method: "POST",
        headers: { Authorization: `Bearer ${env.MEKTUP_API_KEY}`, "Content-Type": "application/json" },
        body: JSON.stringify({ from: "hello@yourapp.com", to, subject, text }),
      });
    }

    // Receive: Mektup posts new mail here
    if (url.pathname === "/inbound") {
      const raw = await request.text();
      if (!(await verify(raw, request.headers.get("X-Mektup-Signature"), env.MEKTUP_WEBHOOK_SECRET))) {
        return new Response("bad signature", { status: 401 });
      }
      const { message } = JSON.parse(raw);
      await env.MAIL_QUEUE.send(message); // or store it in D1, KV, R2
      return new Response(null, { status: 200 });
    }

    return new Response("not found", { status: 404 });
  },
};

async function verify(raw, header, secret) {
  const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret),
    { name: "HMAC", hash: "SHA-256" }, false, ["sign"]);
  const mac = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(raw));
  const hex = [...new Uint8Array(mac)].map((b) => b.toString(16).padStart(2, "0")).join("");
  return header === `sha256=${hex}`;
}

Store MEKTUP_API_KEY and MEKTUP_WEBHOOK_SECRET as secrets, deploy, and set the mailbox webhook to https://your-worker.workers.dev/inbound.

Questions

How do I send email from a Cloudflare Worker?

Workers have no SMTP client built in, so the simplest way is an HTTP email API: one fetch to https://api.usemektup.com/v1/emails with your key from a Worker secret.

How is this different from Cloudflare Email Routing?

Email Routing forwards mail for your domain to other addresses or to an Email Worker. Mektup stores the mail in real mailboxes with webmail and IMAP, sends to any address with DKIM, and posts new mail to your Worker by webhook.

Where do I keep the keys?

As Worker secrets: wrangler secret put MEKTUP_API_KEY and wrangler secret put MEKTUP_WEBHOOK_SECRET.

Start today, or talk to us?

Starter is $20 a month. Agencies get a quote for every client domain on one account.