名称: cloudflare-email-routing 描述: Cloudflare 电子邮件路由,用于通过 Workers 接收和发送电子邮件。适用于电子邮件工作者、转发、允许列表,或遇到电子邮件触发器错误、工作者调用失败、SPF 问题。
关键词: Cloudflare 电子邮件路由, 电子邮件工作者, 发送电子邮件, 接收电子邮件, 电子邮件转发, 电子邮件允许列表, 电子邮件阻止列表, postal-mime, mimetext, cloudflare:email, EmailMessage, ForwardableEmailMessage, EmailEvent, MX 记录, SPF, DKIM, 电子邮件工作者绑定, send_email 绑定, wrangler email, 电子邮件处理器, 电子邮件路由工作者, “Email Trigger not available”, “failed to call worker”, 电子邮件传递失败, 电子邮件未转发, 目标地址未验证 许可证: MIT 元数据: 版本: “2.0.0” 最后验证: “2025-11-18” 生产测试: true 令牌节省: “~60%” 防止错误: 8 包含模板: 0 包含参考: 1
Cloudflare 电子邮件路由
状态: 生产就绪 ✅ | 最后验证: 2025-11-18
什么是电子邮件路由?
两个能力:
- 电子邮件工作者 - 接收和处理传入的电子邮件(允许列表、转发、解析)
- 发送电子邮件 - 从 Workers 发送电子邮件到已验证的地址
两者都是免费的,并一起工作以实现完整的电子邮件功能。
快速开始(10 分钟)
第一部分:启用电子邮件路由
仪表板设置:
- 仪表板 → 域名 → 电子邮件 → 电子邮件路由
- 启用电子邮件路由 → 添加记录并启用
- 创建目标地址:
- 自定义:
hello@yourdomain.com - 目标:您的电子邮件
- 通过电子邮件验证
- 自定义:
- ✅ 基本转发激活
第二部分:接收电子邮件(电子邮件工作者)
安装依赖:
bun add postal-mime@2.5.0 mimetext@3.0.27
创建电子邮件工作者:
// 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('发件人:', message.from);
console.log('主题:', email.subject);
// 转发到目标地址
await message.forward('you@gmail.com');
}
};
配置 wrangler.jsonc:
{
"name": "email-worker",
"main": "src/email.ts",
"compatibility_date": "2025-10-11",
"node_compat": true // 必需!
}
部署和连接:
bunx wrangler deploy
仪表板 → 电子邮件工作者 → 创建地址 → 选择工作者
第三部分:发送电子邮件
添加发送电子邮件绑定:
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2025-10-11",
"send_email": [
{
"name": "SES",
"destination_address": "user@example.com"
}
]
}
从工作者发送:
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);
加载 references/setup-guide.md 以获取完整指南。
关键规则
始终要做 ✅
- 启用 node_compat: true 用于 postal-mime
- 在发送前验证目标地址
- 使用 postal-mime 解析 电子邮件内容
- 使用 mimetext 创建电子邮件
- 检查 message.from 用于允许列表
- 使用 message.forward() 转发(非手动)
- 处理错误(电子邮件传递可能失败)
- 用真实电子邮件测试(不仅仅是仪表板)
- 添加 MX 记录(通过仪表板自动)
- 记录电子邮件活动 用于调试
永远不要做 ❌
- 永远不要跳过 node_compat(postal-mime 需要它)
- 永远不要未经验证发送(传递失败)
- 永远不要在公共代码中硬编码电子邮件地址
- 永远不要跳过解析(原始电子邮件难以处理)
- 永远不要忽略垃圾邮件(实现允许列表/阻止列表)
- 永远不要超过 Gmail 限制(每天 500 封电子邮件到 Gmail)
- 永远不要跳过错误处理(电子邮件可能失败)
- 永远不要手动修改 DNS(使用仪表板)
- 永远不要在日志中暴露电子邮件内容(PII)
- 永远不要假设即时传递(电子邮件是异步的)
常见模式
允许列表
const allowlist = ['approved@domain.com'];
if (!allowlist.includes(message.from)) {
message.setReject('未在允许列表中');
return;
}
await message.forward('you@gmail.com');
阻止列表
const blocklist = ['spam@bad.com'];
if (blocklist.includes(message.from)) {
message.setReject('已阻止');
return;
}
await message.forward('you@gmail.com');
回复电子邮件
const msg = createMimeMessage();
msg.setSender({ addr: 'noreply@yourdomain.com' });
msg.setRecipient(message.from);
msg.setSubject(`回复: ${email.subject}`);
msg.addMessage({
contentType: 'text/plain',
data: '感谢您的电子邮件!'
});
const reply = new EmailMessage(
'noreply@yourdomain.com',
message.from,
msg.asRaw()
);
await env.SES.send(reply);
解析附件
const parser = new PostalMime.default();
const email = await parser.parse(await new Response(message.raw).arrayBuffer());
for (const attachment of email.attachments) {
console.log('文件名:', attachment.filename);
console.log('类型:', attachment.mimeType);
console.log('大小:', attachment.content.byteLength);
}
自定义路由逻辑
async email(message, env, ctx) {
const parser = new PostalMime.default();
const email = await parser.parse(await new Response(message.raw).arrayBuffer());
// 基于主题路由
if (email.subject.includes('[Support]')) {
await message.forward('support@yourdomain.com');
} else if (email.subject.includes('[Sales]')) {
await message.forward('sales@yourdomain.com');
} else {
await message.forward('general@yourdomain.com');
}
}
电子邮件消息属性
传入消息(ForwardableEmailMessage)
message.from // 发件人电子邮件
message.to // 收件人电子邮件
message.headers // 电子邮件头
message.raw // 原始电子邮件流
message.rawSize // 大小(字节)
// 方法
message.forward(address) // 转发到地址
message.setReject(reason) // 拒绝电子邮件
解析的电子邮件(PostalMime)
email.from // { name, address }
email.to // [{ name, address }]
email.subject // 主题行
email.text // 纯文本正文
email.html // HTML 正文
email.attachments // 附件数组
email.headers // 所有头
前 5 个防止的错误
- “Email Trigger not available”:启用 node_compat: true
- 目标未验证:验证所有发送目标
- Gmail 速率限制:每天最多 500 封电子邮件到 Gmail
- SPF permerror:使用仪表板配置 DNS
- 工作者调用失败:检查日志以查找解析错误
使用案例
使用案例 1:支持票务系统
async email(message, env, ctx) {
const parser = new PostalMime.default();
const email = await parser.parse(await new Response(message.raw).arrayBuffer());
// 在数据库中创建票务
await env.DB.prepare(
'INSERT INTO tickets (email, subject, body, created_at) VALUES (?, ?, ?, ?)'
).bind(message.from, email.subject, email.text, Date.now()).run();
// 发送确认
const msg = createMimeMessage();
msg.setSender({ addr: 'support@yourdomain.com' });
msg.setRecipient(message.from);
msg.setSubject('票务已创建');
msg.addMessage({
contentType: 'text/plain',
data: '您的支持票务已创建。'
});
const confirmation = new EmailMessage(
'support@yourdomain.com',
message.from,
msg.asRaw()
);
await env.SES.send(confirmation);
}
使用案例 2:电子邮件通知
export default {
async fetch(request, env, ctx) {
// 用户注册
const { email, name } = await request.json();
const msg = createMimeMessage();
msg.setSender({ name: 'App', addr: 'noreply@yourdomain.com' });
msg.setRecipient(email);
msg.setSubject('欢迎!');
msg.addMessage({
contentType: 'text/html',
data: `<h1>欢迎, ${name}!</h1>`
});
const message = new EmailMessage(
'noreply@yourdomain.com',
email,
msg.asRaw()
);
await env.SES.send(message);
return new Response('欢迎电子邮件已发送!');
}
};
使用案例 3:带有过滤的电子邮件转发
async email(message, env, ctx) {
const parser = new PostalMime.default();
const email = await parser.parse(await new Response(message.raw).arrayBuffer());
// 过滤垃圾关键词
const spamKeywords = ['viagra', 'lottery', 'prince'];
const isSpam = spamKeywords.some(keyword =>
email.subject.toLowerCase().includes(keyword) ||
email.text.toLowerCase().includes(keyword)
);
if (isSpam) {
message.setReject('检测到垃圾邮件');
return;
}
await message.forward('you@gmail.com');
}
何时加载参考
加载 references/setup-guide.md 当:
- 第一次设置电子邮件路由时
- 配置 MX 记录时
- 设置电子邮件工作者时
- 配置发送电子邮件绑定时
- 需要完整指南时
使用捆绑资源
参考 (references/):
setup-guide.md- 完整设置指南(启用路由、电子邮件工作者、发送电子邮件)common-errors.md- 所有 8 个记录的错误及解决方案和预防dns-setup.md- MX 记录、SPF、DKIM 配置指南local-development.md- 本地测试和开发模式
模板 (templates/):
receive-basic.ts- 基本电子邮件接收工作者receive-allowlist.ts- 电子邮件允许列表实现receive-blocklist.ts- 电子邮件阻止列表实现receive-reply.ts- 自动回复电子邮件工作者send-basic.ts- 基本发送电子邮件示例send-notification.ts- 通知电子邮件模式wrangler-email.jsonc- 电子邮件路由的 Wrangler 配置
官方文档
- 电子邮件路由: https://developers.cloudflare.com/email-routing/
- 电子邮件工作者: https://developers.cloudflare.com/email-routing/email-workers/
- 发送电子邮件: https://developers.cloudflare.com/email-routing/email-workers/send-email-workers/
问题?问题?
- 检查
references/setup-guide.md以获取完整设置 - 验证 wrangler.jsonc 中的 node_compat: true
- 确认目标地址已验证
- 检查日志以查找错误