Email routing
Test email routing Workers locally using wrangler dev with simulated incoming emails
Test email routing behavior locally using wrangler dev to simulate incoming emails and verify your routing logic before deploying.
- Sign up for a Cloudflare account ↗.
- Install
Node.js↗.
Node.js version manager
Use a Node version manager like Volta ↗ or nvm ↗ to avoid permission issues and change Node.js versions. Wrangler, discussed later in this guide, requires a Node version of 16.17.0 or later.
Configure your Wrangler file with the email binding:
{ "$schema": "./node_modules/wrangler/config-schema.json", "name": "email-routing-worker", // Set this to today's date "compatibility_date": "2026-04-16", "send_email": [ { "name": "EMAIL" } ]}name = "email-routing-worker"# Set this to today's datecompatibility_date = "2026-04-16"
[[send_email]]name = "EMAIL"import * as PostalMime from 'postal-mime';
export default { async email(message, env, ctx) { // Parse the raw email message const parser = new PostalMime.default(); const rawEmail = new Response(message.raw); const email = await parser.parse(await rawEmail.arrayBuffer());
console.log('Received email:', { from: message.from, to: message.to, subject: email.subject, text: email.text, html: email.html });
// Route based on recipient if (message.to.includes('support@')) { await message.forward('support-team@company.com'); } else { await message.forward('general@company.com'); } },};Start your development server:
npx wrangler devSend a test email using the local endpoint. The request body must be a raw email message in RFC 5322 ↗ format, and the message must include a Message-ID header:
curl --request POST 'http://localhost:8787/cdn-cgi/handler/email' \ --url-query 'from=sender@example.com' \ --url-query 'to=recipient@example.com' \ --data-raw 'Received: from smtp.example.com (127.0.0.1) by cloudflare-email.com (unknown) id 4fwwffRXOpyR for <recipient@example.com>; Tue, 27 Aug 2024 15:50:20 +0000From: "John" <sender@example.com>Reply-To: sender@example.comTo: recipient@example.comSubject: Testing Email Workers Local DevContent-Type: text/html; charset="windows-1252"X-Mailer: CurlDate: Tue, 27 Aug 2024 08:49:44 -0700Message-ID: <6114391943504294873000@ZSH-GHOSTTY>
Hi there'This will output the parsed email structure in the console:
{ "headers": [ { "key": "received", "value": "from smtp.example.com (127.0.0.1) by cloudflare-email.com (unknown) id 4fwwffRXOpyR for <recipient@example.com>; Tue, 27 Aug 2024 15:50:20 +0000" }, { "key": "from", "value": "\"John\" <sender@example.com>" }, { "key": "reply-to", "value": "sender@example.com" }, { "key": "to", "value": "recipient@example.com" }, { "key": "subject", "value": "Testing Email Workers Local Dev" }, { "key": "content-type", "value": "text/html; charset=\"windows-1252\"" }, { "key": "x-mailer", "value": "Curl" }, { "key": "date", "value": "Tue, 27 Aug 2024 08:49:44 -0700" }, { "key": "message-id", "value": "<6114391943504294873000@ZSH-GHOSTTY>" } ], "from": { "address": "sender@example.com", "name": "John" }, "to": [{ "address": "recipient@example.com", "name": "" }], "replyTo": [{ "address": "sender@example.com", "name": "" }], "subject": "Testing Email Workers Local Dev", "messageId": "<6114391943504294873000@ZSH-GHOSTTY>", "date": "2024-08-27T15:49:44.000Z", "html": "Hi there\n", "attachments": []}- Deploy your routing worker: Route emails get started
- See advanced patterns: Email routing examples