为什么绝不应该在API请求中发送电子邮件

为什么绝不应该在API请求中发送电子邮件

💡 原文英文,约1800词,阅读约需7分钟。
📝

内容提要

在API请求中直接发送邮件会导致响应变慢、失败率上升,并受第三方服务影响。正确做法是将邮件发送移至后台任务队列,API只负责提交任务并快速返回。通过队列实现重试、幂等性和优先级管理,确保系统稳定可靠。

🔎

延伸解读

同步发送的隐性成本

在API请求中同步发送邮件,意味着你的响应时间被第三方邮件服务商的服务水平协议(SLA)所绑架。即使你的代码再高效,邮件服务的延迟、限流或故障都会直接转化为用户的等待和错误。这种耦合让API的稳定性不再由自己掌控,而是取决于外部系统的表现。

失败处理的困境

当邮件发送失败时,开发者面临两难:要么让整个请求失败,导致用户看到错误,即使账号可能已创建;要么吞掉异常,导致用户收不到邮件。这两种选择都不理想,尤其在密码重置或确认流程中,数据库显示成功但用户收件箱空空如也,会引发困惑和支持工单。

队列化改造的关键点

将邮件发送移至后台队列后,API只需快速入队并返回,但需注意幂等性和重试策略。使用稳定的jobId或idempotencyKey避免重复发送,对瞬时错误进行指数退避重试,对永久错误快速失败并记录。同时,区分高优先级邮件(如OTP)和低优先级邮件(如营销),确保关键邮件不被阻塞。

扩展思考:哪些任务应移出请求路径

文章指出,不仅邮件,任何涉及第三方网络调用、耗时较长、需要重试或可能失败而不影响主业务的操作,都应移出请求路径。例如Webhook分发、搜索索引、缩略图生成、PDF生成等。核心原则是:API只确认意图并持久化状态,慢操作交给后台worker处理。

Q&A

为什么不应该在API请求中直接发送电子邮件?

因为在API请求中直接发送电子邮件会导致响应时间变慢、失败率上升,并且受第三方邮件服务商的延迟、限流和故障影响。正确做法是将邮件发送移到后台任务队列,API只负责提交任务并快速返回。

在API请求中同步发送邮件会带来哪些具体问题?

具体问题包括:响应时间受第三方SLA影响、失败时面临两难选择(要么让用户看到错误,要么静默丢失邮件)、超时导致级联失败、触发限流、无法干净地重试。

如何将邮件发送改为异步队列处理?

将邮件发送改为异步队列处理的方法是:在API请求中只创建用户并提交一个邮件任务到队列(如BullMQ),然后立即返回响应。由独立的worker进程从队列中取出任务,渲染模板并调用邮件服务商发送邮件。

在异步邮件队列中如何处理重试、失败和幂等性?

处理重试:对瞬时错误(如网络问题、429、503)使用指数退避重试;对永久错误(如无效收件人)快速失败并进入死信队列。处理幂等性:使用稳定的jobId或idempotencyKey,确保重试不会重复发送邮件。

除了邮件,还有哪些任务应该移出请求路径?

其他应该移出请求路径的任务包括:短信发送、webhook分发、搜索索引、缩略图生成、发票PDF创建、CRM同步、AI转录或摘要、慢速报告生成等。这些任务通常涉及第三方网络调用、耗时较长或需要重试。

在发送邮件功能上线前,应该检查哪些问题?

应该检查:用户是否需要等待邮件完成才能看到成功?邮件服务商宕机是否会导致端点故障?数据库写入后邮件发送失败如何恢复?任务重复执行是否会导致重复邮件?OTP和密码重置邮件是否有优先通道?能否在日志、指标或仪表板中看到失败任务?队列深度或失败率飙升时是否告警?

🏷️

标签

➡️

继续阅读