【免费下载链接】mailcheap
Newsletters where you pay for the emails you send, not for dormant subscribers, at a fraction of the price of beehiiv and the like. Open source: self-host it, or use mailcheap.ai.
MailCheap 是一款开源的 Newsletter 邮件营销平台,主打“只为发出的邮件付费,不为沉睡订阅者付费”的按量计费模式。当你点击发送一封有 20 万收件人的活动时,MailCheap 并不会一股脑把邮件塞给邮件服务商,而是借助 Upstash QStash 把发送任务切成 4000 个小批次,按计算好的时间轴均匀铺开,再配合限流、重试与首批发放保护,稳稳地铺开到几个小时里。这篇文章带你拆穿这套批量发送架构的每一个关键零件。
一、为什么 20 万封邮件不能一次性发出?
直接全速发送 20 万封邮件,几乎必然踩雷:
- 触发服务商限流:SES 等邮件服务商有账号级发送速率上限,超限就返回
ThrottlingException,整批邮件被拒; - 损伤发送域名信誉:短时间大量陌生邮箱收到你的邮件,硬反弹率飙升,轻则被暂停发送,重则整个账号被封;
- 新域名尤其脆弱:冷启动的发送域名需要“热身”才能逐步提升配额。
所以核心问题不是“能不能发完”,而是**“以什么节奏发完”**。MailCheap 的答案是:把发送变成一个可计算、可恢复的分布式流水线。
二、总览:从点击“发送”到邮件出栈
整个流程可以概括为五步:
- 建消息:为每个收件人生成一条
Message记录(状态queued),批量写入数据库; - 算节奏:根据账号历史发送量算出本次发送应铺开的总时长;
- 切批次:每50 封为一个批次(
SEND_BATCH_SIZE),20 万封就是 4000 个批次,每个批次是一个独立的 QStash 任务; - 定时投递:QStash 按
notBefore时间逐个把批次“唤醒”到/api/jobs/send-batch接口; - 逐封出栈:批次内逐封检查限流、抑制名单、套餐额度,交给邮件服务商发送,并记录结果。
三、批次化:200000 ÷ 50 = 4000 个 QStash 任务
切批的核心在 lib/sending.js 的publishBatches函数:
- 用
chunk(messageIds, SEND_BATCH_SIZE)把消息 ID 切成每批 50 个; - 每个批次对应一个指向
/api/jobs/send-batch的 QStash 任务,body 只带accountId和messageIds; - 任务用
client.batchJSON以 100 个一组发布到 QStash,避免发布本身成为瓶颈; - 所有批次共享同一个流控键
{ key: "account-<accountId>", parallelism: 1 },同一账号任意时刻只有一个批次在跑,多个账号的批次则并行执行。
接收端 app/api/jobs/send-batch/route.js 做了严格校验:只接受 1 到 100 个(MAX_BATCH_MESSAGES)合法的消息 ID,maxDuration = 300保证 Serverless 函数有 5 分钟处理窗口。
四、铺开算法:发送时长是怎么算出来的
“铺开到几个小时”的时长不是拍脑袋,而是 lib/send-spread.js 里的一套公式,配合 lib/config.js 中的WARMUP配置:
| 参数 | 值 | 含义 |
|---|---|---|
quickEmails | 200 | 不超过 200 封直接全速发 |
days | 30 | 账号从首次活动起进入 30 天热身期 |
growth | 2 → 5 | 热身第 1 天可全速发“已证明量”的 2 倍,第 30 天起为 5 倍 |
minHours | 4 | 需要铺开时,基础时长 4 小时 |
hoursPerDoubling | 4 | 每超出配额一倍,再加 4 小时 |
maxHours | 72 | 最久铺开 72 小时 |
“已证明量”(proven volume)指该账号最近 60 天内、反弹与投诉率健康、且至少发出去一天的最大单场活动量。例如一个已证明量为 10 万、热身第 30 天的账号发 20 万封:
配额 = 100000 × 5 = 500000?不对——若已证明量只有 2 万,配额 = 20000 × 5 = 100000;20 万 ÷ 10 万 = 2 倍 → 时长 = 4 + 4×log₂(2) =8 小时。
随后getBatchStarts把 4000 个批次的启动时间均匀分布:第一批立即执行,最后一批在结束时刻,中间的批次等间隔启动。QStash 的notBefore延迟投递让每个批次“准时上班”,无需任何常驻调度进程。
五、首发保护:新联系人先试 5% 再放行
买了或爬来的邮箱列表是信誉杀手。MailCheap 的对策在 lib/first-send.js 与配置FIRST_SEND:
- 从未收到过邮件的联系人,只先发5%(最少 200 封、最多 2000 封)的一小片,其余标记为
held; - QStash 在 3 小时后投递
/api/jobs/check-first-send检查任务,统计这一小片的送达、反弹、投诉; - 反弹率超过暂停线(2%)→ 活动暂停,等用户清理列表后手动恢复;超过封号线(5%)→ 整个账号被冻结;
- 数据健康 → 放出的
held消息继续占剩余时间轴发完。
这一小片就像“试菜”:出了问题,损失被控制在 2000 封以内,而不是 20 万封。
六、失败与重试:签名验证 + 503 弹性回弹
批量任务跑在 Serverless 上,任何一环都可能挂。MailCheap 用三层机制兜底:
- 签名验证:lib/qstash-route.js 的
withQStashSignature要求所有任务请求必须由 QStash 签名,否则返回 403,防止任何人伪造批次任务刷你的发送配额; - 限流回弹:服务商返回限流(
TooManyRequestsException)时,批次把未发出的消息改回queued,接口返回 503——QStash 看到非 2xx 会自动按退避策略重试;若服务商明确告知恢复时间(retryAfter),则用publishBatchRetry以延迟任务的形式“定点重发”; - 连续失败熔断:一个批次内连续 5 封失败就暂停整场活动并发告警,不再硬碰;任务连续失败 3 次后进入 QStash 死信队列并触发管理员告警。
每封邮件发送前还有一条“认领”操作(queued → sent的原子更新),保证即使任务被重复投递,同一封邮件也只会出栈一次。
七、限流车道:多实例共享一条速率
20 万封邮件会拆成上千个 Serverless 并发实例,如何不让它们集体超速?lib/send-rate.js 实现了“双保险车道”:
- 进程内间隔:每个发送通道(lane)同步预留发送槽位,按配置速率(
sendRatePerSecond)逐封排队; - 跨实例共享:通过 Upstash Redis 的全局限流器,所有实例共享同一个每秒计数;
- Redis 不可用时自动降级为仅进程内限流,超限部分交给服务商限流兜底(反正会被重试)。
这样,无论 QStash 同时唤醒多少个批次,对外的发送速率始终平滑可控。
八、关键文件索引
想深入源码,按这条路径读:
- 发送主流程(建消息、切批、发布任务):lib/sending.js
- 铺开时长与批次启动时间计算:lib/send-spread.js
- QStash 任务签名与失败告警:lib/qstash-route.js
- 批次执行入口:app/api/jobs/send-batch/route.js
- 首发检查任务:app/api/jobs/check-first-send/route.js
- 定时发送(含 QStash 免费层 7 天延迟的接力机制):lib/scheduling.js
- 限流车道:lib/send-rate.js
- 全局常量(批次 50 封、热身 30 天、暂停/封号阈值):lib/config.js
总结
MailCheap 的批量发送架构没有复杂的消息中间件集群,靠的是三个朴素思想的组合:切小(每批 50 封)、铺开(按已证明量对数增长计算时间轴,用 QStash 延迟投递实现)、兜底(签名验证、原子认领、503 重试与首发试菜)。这套设计让 20 万封邮件可以在几小时内平稳出栈,同时把对域名信誉的伤害锁在最小范围内——这正是它敢于按“发出的邮件”而非“订阅者数量”收费的底气所在。
【免费下载链接】mailcheap
Newsletters where you pay for the emails you send, not for dormant subscribers, at a fraction of the price of beehiiv and the like. Open source: self-host it, or use mailcheap.ai.
相关推荐
Seabird终端功能详解:在GNOME桌面中无缝执行Kubernetes命令
Seabird终端功能详解:在GNOME桌面中无缝执行Kubernetes命令 Seabird作为一款原生Kubernetes桌面客户端,为开发者提供了直观的集
终极指南:如何利用Mailpile邮件合并功能批量发送个性化邮件
终极指南:如何利用Mailpile邮件合并功能批量发送个性化邮件 Mailpile是一款免费开源的现代邮件客户端,以其快速响应和用户友好的加密隐私功能著称。本文
后端安全即时通讯PHP邮件发送库SwiftMailer全面入门:架构概览与发送第一封邮件
PHP邮件发送库SwiftMailer全面入门:架构概览与发送第一封邮件 SwiftMailer 是一款功能丰富的 PHP邮件发送库 (Comprehensiv
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考