Skip to content
Development
Skill

/cloudflare-email-routing

Cloudflare Email Routing for receiving/sending emails via Workers. Use for email workers, forwarding, allowlists, or encountering Email Trigger errors, worker call failures, SPF issues.

From plugin
secondsky-claude-skills
219183 skills42 agents62 commands2 MCP
Install
$ npx -y skills add secondsky/claude-skills --skill cloudflare-email-routing --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/cloudflare-email-routing

Context preview

The summary Claude sees to decide when to auto-load this skill.

Cloudflare Email Routing for receiving/sending emails via Workers. Use for email workers, forwarding, allowlists, or encountering Email Trigger errors, worker call failures, SPF issues.

SKILL.md

cloudflare-email-routing.SKILL.md
name: cloudflare-email-routing
description: "Cloudflare Email Routing for receiving/sending emails via Workers. Use for email workers, forwarding, allowlists, or encountering Email Trigger errors, worker call failures, SPF issues."
license: MIT
metadata:
  version: "2.0.0"
  last_verified: "2025-11-18"
  production_tested: true
  token_savings: "~60%"
  errors_prevented: 8
  templates_included: 0
  references_included: 1
  keywords:
    - Cloudflare Email Routing
    - Email Workers
    - send email
    - receive email
    - email forwarding
    - email allowlist
    - email blocklist
    - postal-mime
    - mimetext
    - "cloudflare:email"
    - EmailMessage
    - ForwardableEmailMessage
    - EmailEvent
    - MX records
    - SPF
    - DKIM
    - email worker binding
    - send_email binding
    - wrangler email
    - email handler
    - email routing worker
    - "\"Email Trigger not available\""
    - "\"failed to call worker\""
    - email delivery failed
    - email not forwarding
    - destination address not verified

Cloudflare Email Routing

**Status**: Production Ready ✅ | **Last Verified**: 2025-11-18

---

What Is Email Routing?

Two capabilities:

1. **Email Workers** - Receive and process incoming emails (allowlists, forwarding, parsing) 2. **Send Email** - Send emails from Workers to verified addresses

Both **free** and work together for complete email functionality.

---

Quick Start (10 Minutes)

Part 1: Enable Email Routing

**Dashboard setup:** 1. Dashboard → Domain → **Email** → **Email Routing** 2. **Enable Email Routing** → **Add records and enable** 3. Create destination address:

  • Custom: `hello@yourdomain.com`
  • Destination: Your email
  • Verify via email

4. ✅ Basic forwarding active

Part 2: Receiving Emails (Email Workers)

**Install dependencies:**

bun add postal-mime@2.5.0 mimetext@3.0.27

**Create email worker:**

// src/email.ts
import { EmailMessage } from 'cloudflare:email';
import PostalMime from 'postal-mime';

export default {
  async email(message, env, ctx) {
    const parser = new PostalMime.default();
    const email = await parser.parse(await new Response(message.raw).arrayBuffer());

    console.log('From:', message.from);
    console.log('Subject:', email.subject);

    // Forward to destination
    await message.forward('you@gmail.com');
  }
};

**Configure wrangler.jsonc:**

{
  "name": "email-worker",
  "main": "src/email.ts",
  "compatibility_date": "2025-10-11",  // must be >= 2024-09-23 for nodejs_compat
  "compatibility_flags": ["nodejs_compat"]  // Required! postal-mime needs Node.js compat
}

**Deploy and connect:**

bunx wrangler deploy

Dashboard → Email Workers → **Create address** → Select worker

Part 3: Sending Emails

**Add send email binding:**

{
  "name": "my-worker",
  "main": "src/index.ts",
  "compatibility_date": "2025-10-11",
  "send_email": [
    {
      "name": "SES",
      "destination_address": "user@example.com"
    }
  ]
}

**Send from worker:**

import { EmailMessage } from 'cloudflare:email';
import { createMimeMessage } from 'mimetext';

const msg = createMimeMessage();
msg.setSender({ name: 'App', addr: 'noreply@yourdomain.com' });
msg.setRecipient('user@example.com');
msg.setSubject('Hello!');
msg.addMessage({
  contentType: 'text/plain',
  data: 'Email body here'
});

const message = new EmailMessage(
  'noreply@yourdomain.com',
  'user@example.com',
  msg.asRaw()
);

await env.SES.send(message);

**Load `references/setup-guide.md` for complete walkthrough.**

---

Critical Rules

Always Do ✅

1. **Enable `compatibility_flags: ["nodejs_compat"]`** for postal-mime (requires `compatibility_date >= 2024-09-23`) 2. **Verify destination addresses** before sending 3. **Parse with postal-mime** for email content 4. **Use mimetext** for creating emails 5. **Check message.from** for allowlists 6. **Forward with message.forward()** (not manual) 7. **Handle errors** (email delivery can fail) 8. **Test with real emails** (not just dashboard) 9. **Add MX records** (automatic via dashboard) 10. **Log email activity** for debugging

Never Do ❌

1. **Never skip `nodejs_compat`** (postal-mime requires the Node.js compat flag) 2. **Never send without verification** (delivery fails) 3. **Never hardcode email addresses** in public code 4. **Never skip parsing** (raw email is hard to work with) 5. **Never ignore spam** (implement allowlists/blocklists) 6. **Never exceed Gmail limits** (500 emails/day to Gmail) 7. **Never skip error handling** (emails can fail) 8. **Never modify DNS manually** (use dashboard) 9. **Never expose email content** in logs (PII) 10. **Never assume instant delivery** (email is async)

---

Common Patterns

Allowlist

const allowlist = ['approved@domain.com'];

if (!allowlist.includes(message.from)) {
  message.setReject('Not on allowlist');
  return;
}

await message.forward('you@gmail.com');

Blocklist

const blocklist = ['spam@bad.com'];

if (blocklist.includes(message.from)) {
  message.setReject('Blocked');
  return;
}

await message.forward('you@gmail.com');

Reply to Email

const msg = createMimeMessage();
msg.setSender({ addr: 'noreply@yourdomain.com' });
msg.setRecipient(message.from);
msg.setSubject(`Re: ${email.subject}`);
msg.addMessage({
  contentType: 'text/plain',
  data: 'Thanks for your email!'
});

const reply = new EmailMessage(
  'noreply@yourdomain.com',
  message.from,
  msg.asRaw()
);

await env.SES.send(reply);

Parse Attachments

const parser = new PostalMime.default();
const email = await parser.parse(await new Response(message.raw).arrayBuffer());

for (const attachment of email.attachments) {
  console.log('Filename:', attachment.filename);
  console.log('Type:', attachment.mimeType);
  console.log('Size:', attachment.content.byteLength);
}

Custom Rou

Read more
Ships withsecondsky-claude-skills

145 production-ready skills for Claude Code CLI 🔌 Platform / Harness Support These plugins ship as Claude Code marketplace plugins (.claude-plugin/ manifests) and Codex CLI plugins (.codex-plugin/ manifests).

Get the whole plugin

Other skills on secondsky-claude-skills.