跳至正文
Cloudflare — Cloudflare Email Service:介绍、使用方式与开发接入

Cloudflare Email Service:介绍、使用方式与开发接入

Cloudflare Email Service

AI 参与说明(Agent:Cursor):本文由 Cursor 根据一份 Perplexity 调研导出继续整理。导出稿把 Email Routing 与 Email Sending 收成 Email Service,并给出收发一体、SMTP 与限额表;本稿用 Cloudflare 官方文档、Changelog、Agents SDK 文档与公开仓库逐项回查,纠正过时 SMTP 端点,并补上开发接入、本地调试与完整示例。资料核对于 2026-09-10。Email Sending 仍处于 public beta。运行记录:模型 grok-4.6,提供方 xAI,执行入口 Cursor。reasoning effort 与 CLI 版本未取得运行记录。

结论:开发者要在 Cloudflare 上收发事务邮件,用的是 Email Service,不是 Email security。 Email Service 把出站的 Email Sending 和入站的 Email Routing 收成一套产品。三条出站路径(Workers binding、REST API、SMTP)进入同一条投递管道,共享限额、DKIM / ARC 签名和投递日志。Agent 可以直接用 email() handler 和 Agents SDK 的 onEmail。2026 年 4 月随 public beta 开源的 Agentic Inbox 是目前最显眼的参考实现。

Email Sending is Cloudflare’s first-party transactional email product. Email Routing receives inbound mail and either forwards it to a verified destination address or delivers it to a Worker email() handler. Together they form Email Service. Email Service overview Email Sending public beta, 2026-04-16

官方把两件事说得很直白:密码重置、magic link、发票一旦进垃圾箱,产品体验就坏了;同时邮件正在变成 Agent 与外部世界交互的低摩擦通道,用户转发一封邮件就能触发任务,Agent 做完再回信。这不是“多一个发信 API”,而是把邮箱做成 Workers 生态里与 KV、R2、D1 并列的基础设施。Announcing Email Service Email for agents

阅读前先看这几个词

英文术语中文名称简要解释
Email Service保留原名(产品名称)Cloudflare 开发平台上的收发信产品,由 Email Sending 与 Email Routing 组成
Email Sending保留原名(能力名称)从 Worker、REST API 或 SMTP 发出事务邮件
Email Routing保留原名(能力名称)把域名收到的邮件转发到已验证地址,或交给 Worker
Email security保留原名(产品名称)Cloudflare One 的入站威胁防护,保护已有邮箱,不是发信 API
Area 1保留原名(旧产品名)Cloudflare 收购的邮件安全产品,文档仍单独保留
Workers bindingWorkers 绑定通过 env.EMAIL 发信,不必在 Worker 里放 API Token
send_email配置键名Wrangler 里声明发信 binding 的字段
Routing rule路由规则把一个邮箱地址模式绑定到一个 Destination address 或一个 Worker
Destination address目标地址账号里预先验证、可免费转发或试发的收件地址
ForwardableEmailMessage入站邮件对象email() handler 收到的消息,可 forward / reply / setReject
Suppression list抑制名单硬退信或投诉后不再投递的收件人列表
SMTPS隐式 TLS 的 SMTP连接即 TLS;Email Sending 使用端口 465,不提供 587 STARTTLS
ARCAuthenticated Received Chain转发时保留上游认证结果的签名链,由平台自动写入
Agents SDK保留原名(SDK 名称)Cloudflare 的有状态 Agent 运行时,提供 onEmail 与 sendEmail()
Agentic Inbox保留原名(项目名称)Cloudflare 开源的自托管邮箱与 Email Agent 参考应用
postal-mime保留原名(库名称)解析原始 MIME 的库;读 message.raw 时常用

先分清两条产品线

“Cloudflare 的 email 服务”通常被问成一个产品,实际至少是两条线:

产品解决什么不解决什么入口
Email Service应用和 Agent 收发事务邮件企业邮箱威胁防护、营销群发developers.cloudflare.com/email-service
Email security分析已有 Outlook / Gmail 入站邮件,拦钓鱼、恶意软件、BEC 和垃圾邮件给自己的应用发欢迎信、验证码Cloudflare One Email security

Email security integrates with an existing mailbox provider via API, BCC/Journaling, or MX/Inline; it is a Cloudflare One security control, not a send API for Workers. Area 1 is the earlier product line, and Cloudflare still keeps separate Area 1 documentation. Email security overview

开发者选题里最近变热的,是 Email Service 这一侧:2026-04-16 起 Email Sending 进入 public beta,并和多年已有的 Email Routing 合并宣传。官方同时放出 Agents SDK 的邮件钩子、Wrangler CLI、Email MCP,以及参考应用 Agentic Inbox。Email for agents

flowchart TB
  ask["需要处理邮件?"] --> q1{"是给自己的应用或 Agent 收发,还是保护员工已有邮箱?"}
  q1 -->|应用 / Agent| es["Email Service"]
  q1 -->|员工邮箱防护| sec["Email security / Area 1"]
  es --> send["Email Sending<br/>Workers binding / REST / SMTP"]
  es --> route["Email Routing<br/>转发或 email() handler"]
  send --> tx["welcome / magic link / 订单通知 / Agent 回复"]
  route --> in["support@ / catch-all / Agent 收件"]

Email Service 怎么工作

Email Service requires the zone to use Cloudflare DNS. Onboarding a sending domain adds MX records on the cf-bounce subdomain, plus SPF, DKIM and DMARC records that authorize Cloudflare to send and process bounces. Onboarding Email Routing adds MX on the apex (or chosen domain) so inbound mail arrives at Cloudflare. DNS usually completes in 5–15 minutes, and can take up to 24 hours. Send emails Route emails

入站和出站在同一 Worker 里可以同时出现:HTTP 请求走 fetch,入站邮件走 email(),出站调用 env.EMAIL.send()。站内对 handler 与 binding 的分工,见 Workers:运行时 API、Bindings 与执行模型。

当前官方 Wrangler 配置只需要 send_email 声明出站 binding。入站靠 Dashboard 或 wrangler email routing rules create 把地址指到这个 Worker,不需要再写一个名为 EMAIL_HANDLER 的 email binding。部分二手整理会把后者写进 wrangler.jsonc,与 2026-09-10 的官方文档不一致。

Emails submitted over the Workers binding, the REST API, and SMTP enter the same delivery pipeline: they share limits, receive the same DKIM and ARC signing, and produce the same delivery logs. SMTP

flowchart TB
  mx["域名 MX / SPF / DKIM / DMARC"] --> inbound["Email Routing"]
  inbound --> rule{"Routing rule"}
  rule -->|"转发"| dest["已验证 Destination address"]
  rule -->|"Send to Worker"| handler["email() handler"]
  handler --> parse["postal-mime 解析 MIME"]
  handler --> store["Durable Object / D1 / R2 / Queue"]
  handler --> fwd["message.forward()"]
  handler --> reply["message.reply() 或 env.EMAIL.send()"]
  app["Worker fetch / Queue / Agent"] --> bind["env.EMAIL.send()"]
  rest["外部后端"] --> api["REST API"]
  legacy["Nodemailer / smtplib / PHPMailer"] --> smtp["SMTP SMTPS :465"]
  bind --> sending["Email Sending"]
  api --> sending
  smtp --> sending
  sending --> inbox["收件人收件箱"]

Email Sending:三条出站路径

Email Sending is in public beta and is intended for transactional email only; Cloudflare says marketing and bulk sender tooling are planned, not available now. Email Service FAQ Public beta changelog

路径适用场景鉴权成功返回
Workers binding env.EMAIL.send()代码已经跑在 Worker / Agents SDKsend_email binding,不必放 API Token{ messageId }
REST APINode、Python、Go 或其它后端Bearer API Tokendelivered / permanent_bounces / queued
SMTP smtp.mx.cloudflare.net:465现有 SMTP 客户端(Nodemailer、smtplib、PHPMailer、JavaMail)用户名固定为 api_token,密码为 API TokenSMTP 250,正文后返回 Message-ID

The from address must belong to a domain onboarded for Email Sending. Before that domain is onboarded, you can only send to verified destination addresses in the account; after onboarding, you can send to arbitrary recipients on the Workers Paid plan. Limits

Workers binding

jsonc
{
  "name": "transactional-mail",
  "main": "src/index.ts",
  "compatibility_date": "2026-09-10",
  "send_email": [
    {
      "name": "EMAIL",
      "remote": true
    }
  ]
}

"remote": true lets wrangler dev call the real Email Service. Real mail will be sent, so use addresses you control. Run npx wrangler types after adding the binding; do not hand-write SendEmail. Workers API Agents email channel

ts
interface Env {
  EMAIL: SendEmail;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    if (url.pathname !== "/welcome") {
      return new Response("Not Found", { status: 404 });
    }

    try {
      const result = await env.EMAIL.send({
        to: "user@example.com",
        from: { email: "welcome@yourdomain.com", name: "Example App" },
        replyTo: "support@yourdomain.com",
        subject: "Welcome",
        html: "<h1>Welcome</h1><p>Thanks for signing up.</p>",
        text: "Welcome. Thanks for signing up.",
      });
      return Response.json({ messageId: result.messageId });
    } catch (error) {
      const code = (error as { code?: string }).code;
      if (code === "E_SENDER_NOT_VERIFIED" || code === "E_SENDER_DOMAIN_NOT_AVAILABLE") {
        return Response.json({ error: code }, { status: 400 });
      }
      if (code === "E_RATE_LIMIT_EXCEEDED" || code === "E_DAILY_LIMIT_EXCEEDED") {
        return Response.json({ error: code }, { status: 429 });
      }
      throw error;
    }
  },
} satisfies ExportedHandler<Env>;

官方 Workers API 把 from 写成 string | EmailAddress,其中 EmailAddress.email 是地址字段。结合 to / cc / bcc 的收件人总数不超过 50;单封出站邮件(含附件)默认不超过 5 MiB,只有发往 verified destination addresses 时才放到 25 MiB。附件最多 32 个。新代码优先用结构化的 send(),旧的 EmailMessage + mimetext 仅在已经持有 RFC 5322 原文时保留。Workers API Limits

常见错误码(Workers binding 抛出字符串 code):

code含义
E_SENDER_NOT_VERIFIED / E_SENDER_DOMAIN_NOT_AVAILABLE发件域名未完成 Email Sending 接入
E_RECIPIENT_NOT_ALLOWED收件人不在 binding 允许列表
E_RECIPIENT_SUPPRESSED收件人已在 Suppression list
E_TOO_MANY_RECIPIENTSto + cc + bcc 超过 50
E_CONTENT_TOO_LARGE超过 5 MiB(或 verified destination 的 25 MiB)
E_RATE_LIMIT_EXCEEDED / E_DAILY_LIMIT_EXCEEDED触发速率或日配额
E_HEADER_NOT_ALLOWED / E_HEADER_USE_API_FIELD自定义 header 不在允许列表,或应走独立 API 字段

可以用 destination_address 或 allowed_destination_addresses 收紧某个 binding 能发往哪里,避免一个 Worker 拿到无限制发信能力。Configure send bindings

模板不必绑死在 Cloudflare 上。官方示例直接传 HTML 字符串;也可以先用 @react-email/render 得到 html 和 text,再交给 env.EMAIL.send()。当前一手教程以 User signup flow 为准。

REST API

The current REST endpoint is POST https://api.cloudflare.com/client/v4/accounts/{account_id}/email/sending/send. Authenticate with a token that can send email. A successful body groups recipients into delivered, permanent_bounces, and queued; this is not the Workers binding’s { messageId }. REST 用数字错误码(例如限流 10004),Workers binding 用字符串 code。 REST API

bash
curl "https://api.cloudflare.com/client/v4/accounts/{account_id}/email/sending/send" \
  --header "Authorization: Bearer <API_TOKEN>" \
  --header "Content-Type: application/json" \
  --data '{
    "to": "recipient@example.com",
    "from": "welcome@yourdomain.com",
    "subject": "Welcome to our service!",
    "html": "<h1>Welcome</h1><p>Thanks for signing up.</p>",
    "text": "Welcome! Thanks for signing up."
  }'

2026-04-16 的博客示例曾写过 /email-service/send 路径。以 2026-06-09 更新的 REST API 文档为准,当前路径是 /email/sending/send。

SMTP:只提供 465 隐式 TLS

Authenticated SMTP submission became available in beta on 2026-06-08. The current endpoint is smtp.mx.cloudflare.net:465 with implicit TLS (SMTPS). Plaintext SMTP, opportunistic STARTTLS on port 587, and unauthenticated relay on port 25 are not supported for outbound submission. Port 25 is reserved for inbound Email Routing. SMTP SMTP changelog

部分入门页摘要仍出现 smtp.cloudflare.email:587。以 SMTP 参考页(标注 2026-06-09)和 2026-06-08 Changelog 为准。

配置项值
Hostsmtp.mx.cloudflare.net
Port465
SecurityImplicit TLS / SMTPS
AUTHPLAIN(优先)或 LOGIN
Username字面量 api_token,不是 Token 本身
Password带 Email Sending: Edit 权限的 API Token

Anyone with that token can send from any onboarded domain on the matching account. Prefer an account-owned token, and treat it as a credential. SMTP

js
import nodemailer from "nodemailer";

const transporter = nodemailer.createTransport({
  host: "smtp.mx.cloudflare.net",
  port: 465,
  secure: true,
  auth: {
    user: "api_token",
    pass: process.env.CF_API_TOKEN,
  },
});

const info = await transporter.sendMail({
  from: '"Acme" <welcome@yourdomain.com>',
  to: "user@example.com",
  subject: "Welcome to Acme",
  text: "Thanks for signing up.",
  html: "<h1>Welcome to Acme</h1><p>Thanks for signing up.</p>",
});

最小 curl:

bash
curl --ssl-reqd \
  --url "smtps://smtp.mx.cloudflare.net:465" \
  --user "api_token:$CF_API_TOKEN" \
  --mail-from "welcome@yourdomain.com" \
  --mail-rcpt "recipient@example.com" \
  --upload-file mail.txt

单次会话 RCPT TO 不超过 50,EHLO 声明的 SIZE 是 5 MiB,AUTH 超时 30 秒,DATA 超时 300 秒。账户级配额与 REST / Workers binding 共享。常见失败:用户名不是 api_token 会 535 5.7.8;MAIL FROM 域名未接入会 550 5.7.1;消息超过 5 MiB 会 552 5.3.4。客户端必须按 465 隐式 TLS 连接,不能改成 587 STARTTLS。SMTP SMTP examples

本地或沙箱里的 coding agent 也可以不写 Worker,直接用 Wrangler:

bash
npx wrangler email sending enable yourdomain.com
npx wrangler email sending dns get yourdomain.com
npx wrangler email send \
  --from "agent@yourdomain.com" \
  --to "you@example.com" \
  --subject "Build completed" \
  --text "The staging deploy finished."

Email for agents 把同一套能力接到 Cloudflare MCP,因此不在 Workers 上跑的 Agent 也能发信。

Email Routing:入站邮件怎么进 Worker

Email Routing is available on Workers Free and Workers Paid. Inbound volume is unlimited; a routing rule maps one address pattern to either one destination address or one Worker. Destination addresses are account-scoped and capped at 200. Inbound messages larger than 25 MiB are rejected. Pricing Limits

开通顺序:Dashboard 进入 Compute → Email Service → Email Routing → Onboard Domain → 添加并验证 Destination address → 创建 Routing rule(Email pattern、Action、Destination)。也可以用 wrangler email routing enable / wrangler email routing rules create。

email() handler 不需要单独的收信 binding。message 的类型是 ForwardableEmailMessage:

ts
interface ForwardableEmailMessage {
  readonly from: string;
  readonly to: string;
  readonly headers: Headers;
  readonly raw: ReadableStream;
  readonly rawSize: number;
  readonly canBeForwarded: boolean;
  setReject(reason: string): void;
  forward(rcptTo: string, headers?: Headers): Promise<EmailSendResult>;
  reply(message: EmailMessage): Promise<EmailSendResult>;
}
  • from / to 是 SMTP 信封地址。from 比邮件头更可信,因为头可以伪造。
  • raw 是一次性 ReadableStream。第二次读取会得到空内容,解析前先 arrayBuffer()。
  • forward(rcptTo) 只能发到已经验证的 Destination address。自定义 header 只保留 X- 前缀,其它会被去掉。
  • setReject(reason) 以永久 SMTP 错误拒绝。
  • reply() 走同一条 SMTP 会话并保持 Message-ID 链,但限制很严,见下一小节。延迟回复应改存状态,再用 env.EMAIL.send()。

Email handler

message.reply() throws unless all of these are true: the inbound message has a valid DMARC result; this event has not already replied; the reply recipient matches the original sender; the outgoing sender domain matches the receiving domain; the inbound References header has at most 100 entries. Email handler

因此:需要立刻线程化回信、且满足 DMARC 时用 reply();需要异步、人审或绕过这些限制时用 env.EMAIL.send(),并自己设 In-Reply-To / References。

ts
import PostalMime from "postal-mime";

interface Env {
  EMAIL: SendEmail;
  TICKETS: Queue;
}

export default {
  async email(message, env): Promise<void> {
    const raw = await new Response(message.raw).arrayBuffer();
    const parsed = await PostalMime.parse(raw);
    const subject = parsed.subject ?? message.headers.get("subject") ?? "";

    if (!message.to.toLowerCase().includes("support@")) {
      message.setReject("Unknown recipient");
      return;
    }

    const extra = new Headers();
    extra.set("X-Original-Recipient", message.to);
    extra.set("X-Processed-By", "support-worker");
    await message.forward("team@example.com", extra);

    await env.TICKETS.send({
      from: message.from,
      subject,
      text: parsed.text ?? "",
    });
  },
} satisfies ExportedHandler<Env>;

This example is a complete handler skeleton; it is not a production inbox. Immediate auto-replies can create mail loops. Production code should skip noreply / auto-submitted mail (Agents SDK 提供 isAutoReplyEmail()),并把必须送达的工作写入 Queues 或 Workflows,不要只挂在 ctx.waitUntil() 上。

一条 routing rule 只能指向一个目标。同一个地址要同时入库和转发给多人时,用 Worker 对每个已验证地址调用一次 forward(),或 Promise.all。

Emails sent with the send_email binding show up as dropped in the Email Routing summary even when delivery succeeded. Track outbound success in Email Sending metrics and logs, not the routing dashboard. Limits

Subaddressing (user+detail@example.com) 已支持:user@example.com 的规则会接住 +detail,细节可留给 Worker 或 Agent 做分类。Subaddressing changelog, 2025-07-21

开发接入:从本地到一条完整用户流

1. 域名与 Wrangler

  1. 域名必须使用 Cloudflare DNS。
  2. npx wrangler email routing enable yourdomain.com 与 npx wrangler email sending enable yourdomain.com(或 Dashboard 的 Onboard Domain)。
  3. npx wrangler email sending dns get yourdomain.com 核验 MX、SPF、DKIM、DMARC。
  4. 先验证至少一个 Destination address,在发送域名生效前用它做免费试发。
  5. 在 wrangler.jsonc 声明 send_email,然后 npx wrangler types。

2. 本地触发 email() handler

wrangler dev 会暴露 POST /cdn-cgi/local/email。可以用 curl 把一封原始邮件打进本地 Worker,不必先改 MX。Local development for Email Workers

bash
npx wrangler dev

curl -X POST 'http://localhost:8787/cdn-cgi/local/email' \
  --url-query 'from=sender@example.com' \
  --url-query 'to=support@yourdomain.com' \
  --header 'Content-Type: application/json' \
  --data-raw 'From: sender@example.com
To: support@yourdomain.com
Subject: Testing Email Workers Local Dev

Hi there'

出站若配置了 "remote": true,本地 EMAIL.send() 会打到真实 Email Service。测试地址必须是你控制的邮箱。

3. 注册信与验证链接

官方 User signup flow 用两个 KV namespace 保存用户和 1 小时过期的验证 token,POST /signup 连发欢迎信和验证信,GET /verify 核销 token。下面是同一条路径的压缩版,完整代码以官方页为准。

ts
interface Env {
  EMAIL: SendEmail;
  USERS: KVNamespace;
  VERIFICATION_TOKENS: KVNamespace;
  DOMAIN: string;
  COMPANY_NAME: string;
}

async function handleSignup(request: Request, env: Env): Promise<Response> {
  const { email, firstName } = (await request.json()) as {
    email?: string;
    firstName?: string;
  };
  if (!email || !firstName) {
    return Response.json({ error: "Invalid input" }, { status: 400 });
  }
  if (await env.USERS.get(email)) {
    return Response.json({ error: "User already exists" }, { status: 409 });
  }

  const token = crypto.randomUUID();
  await env.USERS.put(email, JSON.stringify({ email, firstName, verified: false }));
  await env.VERIFICATION_TOKENS.put(token, email, { expirationTtl: 3600 });

  const verificationUrl = `https://${env.DOMAIN}/verify?token=${token}`;
  await env.EMAIL.send({
    to: email,
    from: `noreply@${env.DOMAIN}`,
    subject: "Please verify your email address",
    html: `<p>Hi ${firstName}, <a href="${verificationUrl}">verify your email</a>. This link expires in 1 hour.</p>`,
    text: `Hi ${firstName}, verify: ${verificationUrl}`,
  });

  return Response.json({ success: true }, { status: 201 });
}

验收:用自己的邮箱走完 signup → 收到两封信(完整示例会再发欢迎信)→ 一小时内打开链接 → KV 中 verified: true;过期 token 返回 400。不要在 fetch 里用 waitUntil 发送验证信,验证信失败应让请求失败。

4. 入站工单闭环

一个可落地的开发顺序:

sequenceDiagram
  participant User
  participant MX as Email Routing
  participant W as Worker email()
  participant Q as Queue
  participant C as Queue consumer
  participant ES as Email Sending
  User->>MX: 发到 support@yourdomain.com
  MX->>W: ForwardableEmailMessage
  W->>W: postal-mime 解析
  W->>Q: 投递工单 payload
  W-->>User: 可选 message.reply()
  Q->>C: 至少一次消费
  C->>C: 写 Durable Object / 外部工单
  C->>ES: env.EMAIL.send() 带工单号
  ES-->>User: 确认信

Worker 热路径只做:校验收件人、缓冲 raw、解析、forward 给值班邮箱、投递 Queue。摘要、Workers AI 分类、创建 Jira/Linear、延迟回信都放到 consumer。这样 CPU 超限时入站邮件不会整封丢失,Free 计划上的 EXCEEDED_CPU 也更容易隔离。

5. 自定义 Header

Email Service 对 header 采用允许列表。Date、Message-ID、DKIM-Signature、ARC-*、Return-Path 等由平台生成,写入 headers 会 E_HEADER_NOT_ALLOWED。From / To / Subject / Reply-To 必须走独立字段。可设置的包括 In-Reply-To、References、List-Unsubscribe、Auto-Submitted,以及任意 X- 前缀。非 X- 的允许 header 最多 20 个,自定义 header 合计不超过 16 KB。整封请求若含非法 header 会被拒绝,不会静默删头后继续发送。Email headers

Agents SDK:把邮箱当成 Agent 的接口

A chatbot answers in the current turn. An email-native agent can receive mail, persist state in a Durable Object, do longer work, then reply later. Email for agents Email agent example

ts
import { Agent, callable, routeAgentEmail } from "agents";
import { createAddressBasedEmailResolver, type AgentEmail } from "agents/email";
import PostalMime from "postal-mime";

export class SupportAgent extends Agent {
  @callable()
  async sendWelcomeEmail(to: string) {
    await this.sendEmail({
      binding: this.env.EMAIL,
      to,
      from: "support@yourdomain.com",
      replyTo: "support@yourdomain.com",
      subject: "Welcome",
      text: "Thanks for signing up. Reply to this email if you need help.",
    });
  }

  async onEmail(email: AgentEmail) {
    const raw = await email.getRaw();
    const parsed = await PostalMime.parse(raw);

    this.setState({
      ...this.state,
      ticket: {
        from: email.from,
        subject: parsed.subject,
        messageId: parsed.messageId,
      },
    });

    await this.replyToEmail(email, {
      fromName: "Support Agent",
      body: "Thanks for your email. We received it.",
    });
  }
}

export default {
  async email(message, env) {
    await routeAgentEmail(message, env, {
      resolver: createAddressBasedEmailResolver("SupportAgent"),
    });
  },
} satisfies ExportedHandler<Env>;

要点:

  1. createAddressBasedEmailResolver("SupportAgent") 按收件地址把邮件送到对应 Agent 实例;support@、sales@ 可以是不同实例,不必先建多个邮箱产品。
  2. sendEmail() 会写入 X-Agent-Name 和 X-Agent-ID。传入 secret 时用 HMAC-SHA256 签名,后续回复经 createSecureReplyEmailResolver 回到同一个实例,避免伪造头把邮件打到任意 Agent。
  3. replyToEmail() 只能在活的 onEmail 调用里使用。人审之后再回、Queue 消费后再回,应把 from / messageId / subject 写入 state,然后用 sendEmail() 并设置 inReplyTo。
  4. Durable Objects 保存会话状态,所以“邮箱”可以同时是 Agent 的记忆,而不必先外接另一套向量库。对象模型见 Durable Objects 使用方式与接口整理。

价格、配额与接入条件

整理日期 2026-09-10,依据官方定价与限额页(定价页标注 2026-06-09 更新):

项目Workers FreeWorkers Paid
Email Routing 入站不限量不限量
Email Sending 出站到任意收件人不可用每月 3,000 封,超出后每 1,000 封 $0.35
发到账号内 verified destination addresses免费,不计入月配额和日限额同左

Pricing

其它会直接影响实现的边界:

  • 新账号有较保守的 daily sending limits,随发送声誉上升;需要提前提高时走官方限额申请表。
  • 被 API 边界拒绝的请求(含 Suppression list)不计入月配额;硬退信或已被 Email Service 接受的邮件计入。
  • 每个 zone 最多 30 个配置了 Routing 或 Sending 的域名(含 apex)。
  • 处理入站邮件的 Worker 仍占用标准 CPU / 内存。Free 计划上复杂 handler 可能 EXCEEDED_CPU。
  • You must use Cloudflare DNS. 事务邮件仍须遵守 CAN-SPAM、GDPR、CASL 等适用法规,并提供退订与投诉处理。

近期比较热的项目:Agentic Inbox 以及其它自托管邮箱

The project that matches “最近好像看到什么比较火” is Cloudflare’s own Agentic Inbox. It was published with the Email Sending public beta on 2026-04-16, and on 2026-09-10 GitHub reported 7,362 stars and 947 forks.

Agentic Inbox 把 Email Service 嵌进一个可部署的邮箱客户端:

层用到的 Cloudflare 能力
入站Email Routing catch-all → Worker
出站send_email binding
每个邮箱的状态Durable Object + SQLite
附件R2
Email AgentAgents SDK AIChatAgent + Workers AI
生产鉴权Cloudflare Access;README 写明这是唯一信任边界,没有按邮箱授权

它会自动给新邮件起草回复,但发送前必须人工确认。仓库也暴露 /mcp,外部 Agent 可以起草、等人审。这是参考应用,不是 Cloudflare 托管的 Gmail 替代品:邮件数据在你自己的账号里,生产环境必须先配 Access。README 仍有部分链接指向旧的 Email Routing 路径,接入时以当前 Email Service 文档为准。Agentic Inbox README Email for agents

同一波自托管邮箱里,社区项目 Mailflare 在 2026-09-10 有 2,877 stars。它同样跑在你的 Cloudflare 账号里,用 Email Routing 收信、Email Sending 发信,数据放在自己的 D1 与 R2,面向个人和团队邮箱,而不是官方 Agent 参考实现。

选型时不要把这些项目和 Email Service 本身并列成“又一个 Cloudflare 官方邮件产品”:

需求直接用 Email Service再考虑参考应用
注册信、magic link、订单通知Workers binding 或 REST不需要完整邮箱 UI
把 support@ 变成 Agent 工单email() + Agents SDK需要人审界面时再看 Agentic Inbox
给自定义域名做一个自托管收件箱Routing + DO/D1/R2 最小实现Agentic Inbox / Mailflare
保护公司 Outlook / Gmail不走 Email ServiceEmail security

适合 / 不适合

现在就可以上:

  • 入站自动化:工单转化、附件入库、按域名拒收。
  • 发往账号内 verified destination addresses 的内部通知:免费且不占月配额。
  • Agent 的邮件入口:onEmail + 人审后再 sendEmail()。

可以接入但要控制预期:

  • 面向真实用户的验证码、密码重置、订单通知。Email Sending 仍是 public beta,配额和限流可能调整,先在低风险链路看送达率。

暂不建议:

  • 新闻信、促销、批量营销和复杂订阅者分段。官方明确当前只做 transactional email;这些是 Resend、Postmark、Customer.io 的强项。
  • 员工邮箱的钓鱼与 BEC 防护。那是 Email security。
  • 把 Cloudflare 当完整的企业邮箱托管(日历、通讯录、IMAP 客户端生态)。
  • 尚未把 DNS 迁到 Cloudflare 的域名。
  • 把 ctx.waitUntil(env.EMAIL.send()) 当成可靠投递。

和站内其它专题的关系:Email Routing 只是又一种 Worker handler;发信是一种 binding。对象协调仍用 Durable Objects,可靠异步仍用 Queues / Workflows。不要因为 Agentic Inbox 把这些叠在一起,就把“邮箱”实现成一个巨大的 fetch。

落地检查清单

  1. 确认需求属于 Email Service 还是 Email security。
  2. 域名使用 Cloudflare DNS;分别执行 wrangler email routing enable 与 wrangler email sending enable,或在 Dashboard 的 Compute → Email Service 接入。
  3. 用 wrangler email sending dns get / wrangler email routing dns get 核验 MX、SPF、DKIM、DMARC。
  4. 先验证至少一个 Destination address,在域名发送能力生效前用它做试发。
  5. 在 wrangler.jsonc 只声明 send_email,运行 npx wrangler types;不要抄未经官方确认的 email handler binding。
  6. 入站规则:需要代码处理时指向 Worker,只想进已有 Gmail/Outlook 时指向 Destination address。
  7. 解析 MIME 前缓冲 message.raw;同时提供 html 与 text。
  8. message.reply() 前确认 DMARC、只回一次、发件域名匹配;否则改用 EMAIL.send()。
  9. SMTP 使用 smtp.mx.cloudflare.net:465、用户名 api_token,不要配 587 STARTTLS。
  10. 出站成功看 Email Sending 指标,不要被 Routing 摘要里的 dropped 误导。
  11. 用 wrangler dev 的 /cdn-cgi/local/email 测入站,用自己的邮箱测出站。
  12. 生产 Agent 回复必须有人审或明确的自动回复策略,并处理 auto-reply 循环。
  13. 部署 Agentic Inbox 前先配 Cloudflare Access,并阅读其“所有通过 Access 的人能看到全部邮箱”的信任模型。

关联阅读

参考资料

本文共 5994 字,创建于 Sep 10, 2026
博客助手

正在打开博客助手…