MakiSend 如何在 Cloudflare 上运行
一个 Worker、一个数据库、一个队列和一个持久 Workflow。无需维护任何常驻服务,全部运行在你自己的 Cloudflare 账号上。
跟随一封邮件
选择你的 SMTP 服务商那边会发生什么,然后发送。每一站都是一个 Cloudflare 产品。
- 你的应用POST /send-email
- WorkerWorkers
- 数据库D1
- 队列Queues
- WorkflowWorkflows
- 你的 SMTPTCP sockets
- 收件箱已送达
- 死信Queues (DLQ)
按“发送”跟随一封邮件。
背后的 Cloudflare 产品
Workers(Cloudflare 文档,在新标签页中打开)
一个 Worker 运行所有内容:Hono API、登录、控制台和投递代码。
nodejs_compat 让 nodemailer 及其 SMTP 客户端无需改动即可运行。没有服务器,也没有容器。
Static Assets(Cloudflare 文档,在新标签页中打开)
从同一个 Worker 提供控制台(Astro 构建),与 API 同源。
同源意味着没有 CORS,只需记住一个 URL。
D1(Cloudflare 文档,在新标签页中打开)
数据库:邮件日志和历史、加密的内容和附件、SMTP 配置、API keys、模板、账号。
收件人、正文、附件和 SMTP 凭据在写入前都经过 AES-256-GCM 加密。Schema 由 Drizzle 迁移管理。
Queues(Cloudflare 文档,在新标签页中打开)
将 API 与投递解耦:邮件 id 一进入队列,请求就结束。
每批最多 10 条,消费者重试 3 次,间隔 30 秒,之后进入死信队列(makisend-send-email-dlq)。
Workflows(Cloudflare 文档,在新标签页中打开)
每封邮件一次持久运行。它的 id 就是邮件 id,因此同一封邮件不可能被两次运行重复发送。
4 次 SMTP 尝试,间隔 30 秒,重启后依然继续。永久错误(auth、TLS、DNS、5xx)会立即停止。每一步都写入这封邮件的历史。
TCP sockets(Cloudflare 文档,在新标签页中打开)
Worker 自己通过 TLS 打开到你的服务商的 SMTP 连接。
端口 465、587、2465、2525 和 2587。端口 25 被 Cloudflare 封锁。连接从共享的 Cloudflare IP 发出。
Email Service(Cloudflare 文档,在新标签页中打开)
SMTP 之外的另一种选择:使用 smtp.mx.cloudflare.net 的配置通过 Worker 的 send_email binding 发送。
不需要 SMTP 密码;发件地址必须使用已接入 Cloudflare Email Sending 的域名。
Cron Triggers(Cloudflare 文档,在新标签页中打开)
无需额外服务的后台任务:健康检查、更新检查和密钥轮换。
每天 03:17 UTC,以及每小时第 17 分钟(见下文)。
Workers Logs(Cloudflare 文档,在新标签页中打开)
Worker 的请求和调用日志,显示在你的 Cloudflare 控制台中。
在 wrangler.jsonc 中开启。邮件内容永远不会被记录。
定时运行的任务
- 每天 03:17 UTC
- 测试每个 SMTP 配置并记录结果,然后在 GitHub 上检查是否有新的 MakiSend 版本(除非关闭了 UPDATE_CHECK)。
- 每小时第 17 分钟
- 密钥轮换:分小批重新加密仍使用旧 ENCRYPTION_KEY 的存储数据。
依赖它之前需要了解的事
- 没有固定的出站 IP:要求 IP 白名单的服务商会拒绝来自 Worker 的发送。
- 发送是异步的:202 表示已入队,而不是已送达。结果见日志和控制台。
- 每个配置一个 SMTP 服务商,没有自动故障切换。暂不支持退信、打开和点击跟踪。
- 送达率取决于你的发件域名(SPF、DKIM、DMARC)和你的服务商,而不是 Cloudflare。
完整的设计、数据模型和图表见 README 和 docs/ARCHITECTURE.md。