指南 · Mailgun API

产品团队应如何安全地实现 Mailgun API?

将 Mailgun API 放在经过授权的服务端 worker 之后实现。验证确切的发信域名,使用可用的最小权限 API 凭据,创建持久化的内部发送任务,并向按域名划分的 Messages 端点提交 multipart 表单数据。保存 Mailgun 返回的消息标识符,在处理 Webhook 请求之前先对其进行身份验证,对事件去重,并在发送时执行退信、投诉和退订规则。将 API 受理、Mailgun 处理、收件服务器投递和进入收件箱作为不同的状态分开处理。

调用 Mailgun 之前先定义范围明确的产品操作

从一个经过批准的产品事件开始,例如账户验证、收据、安全告警或收件人主动请求的通知。将 Mailgun 放在受信任的应用服务或队列 worker 之后,而不是把服务商凭据或任意的邮件表单暴露给浏览器和移动客户端。在构造服务商字段之前,先对调用方、租户、发件人身份、收件人、邮件类别和模板进行授权。持久化一条内部出站记录,包含稳定的事件键、租户、模板版本、经批准的地址和初始状态。这条记录是决策依据;Mailgun 只是传输依赖。将业务意图与服务商请求体分离,可以让重试和审计更安全,也为日后迁移服务商保留可能。事务性流量和依赖用户同意的流量应在数据模型中保持区分,这样收件人偏好、抑制规则和信誉事故就不会沦为非正式的模板约定。

验证确切的发信域名和 DNS 记录

添加一个由组织控制的域名,并发布 Mailgun 当前为验证、身份验证、跟踪以及实际选用的收信功能所提供的 DNS 记录。修改 DNS 之前,先检查现有的 SPF 和 DMARC 记录。不要在同一个主机名上创建第二条 SPF 记录,也不要在未经负责人同意的情况下替换组织级的 DMARC 策略。验证工作负载实际使用的 From 和签名身份,而不仅仅是相邻的父域名。当归属、流量隔离或迁移有需要时,使用专用的子域。Mailgun 报告验证通过后,检查一封受控的已收邮件中的可见 From 地址、DKIM 签名域名、退信路径、身份验证结果和回复行为。服务商验证通过只能说明其配置检查已通过,并不能证明收件人同意、目标服务器接收、发件人信誉或进入收件箱。请在服务商控制台之外保存 DNS 变更历史和回滚说明。

使用限定作用域的凭据和正确的区域端点

Mailgun 文档说明其 API 使用 HTTP Basic 身份验证,不同的 API 凭据具有不同的权限和用途。发信 worker 应只获得经批准的域名和操作所需的凭据。将主账户密钥、域名发信密钥、Webhook 签名密钥以及较低环境的凭据分开。将机密信息直接保存在托管的密钥存储中,只暴露给需要它们的服务端进程。绝不要把凭据放在客户端代码、源代码管理、URL、日志、分析系统、模板、工单或提示词中。根据账户所在区域选择文档中给出的 API 基础 URL,而不要默认所有域名都使用同一个主机。演练轮换流程:创建一个作用域相同的替换凭据,更新 worker,验证受控流量和事件,然后吊销旧凭据。对意外的身份验证和授权失败设置告警,因为它们可能意味着凭据被吊销、区域错误、作用域漂移或凭据泄露。

构建一个可靠的 Messages API 请求

Mailgun 按域名划分的 Messages 端点接受 multipart 表单字段,包括发件人、收件人、主题、纯文本或 HTML 内容,以及模板、附件、邮件头、标签、收件人变量、跟踪和定时投递等文档所列选项。只开放产品需要的那部分。校验地址语法和租户归属,限制收件人和附件数量,拒绝换行符注入,并使用带类型的变量渲染经过批准的模板。不要在标签、自定义变量或邮件头中放置机密信息或不必要的个人数据,因为服务商的事件和活动视图可能会独立于邮件内容展示这些元数据。从已认领的内部任务发起提交,并将 Mailgun 返回的消息标识符与对应的那次尝试一起保存。将服务商特有的选项名称限制在一个适配器内。业务代码应只接收一个范围明确的“已受理”“已拒绝”或“不确定”结果,而不需要了解 Mailgun 的每个字段和错误格式。

围绕受理和不确定性设计重试

重试之前先对响应进行分类。对于格式错误的字段、未授权的域名、无效凭据、权限失败和永久性策略错误,应修复问题而不是重放请求。对符合条件的传输失败、服务商服务器错误和被限速的请求,使用带抖动的指数退避、有限的尝试次数和队列时长限制进行重试。Mailgun 返回受理响应,表示服务商已接受该提交请求并进行处理;它并不能证明目标服务器已接收邮件。客户端超时属于不确定情况,因为即使 worker 没有收到响应,Mailgun 也可能已经受理了请求。将该任务置于未知状态,查找已保存的关联数据或后续事件,并在重新发送之前应用明确的对账规则。使用 Mailgun 传输并不能免去对稳定的应用事件键、单一 worker 认领、尝试历史和重复风险控制的需要。按凭据、域名、模板、租户和目标服务商对重复出现的失败设置告警。

解析之前先验证 Webhook 请求

配置一个 HTTPS Webhook 端点,并原样保留 Mailgun 签名流程所用的字段。Mailgun 文档说明了 timestamp、token 以及使用 Webhook 签名密钥生成的 signature。在接受事件之前,使用常量时间比较校验签名,并拒绝超出应用时效窗口的时间戳。根据需要记录 token 或事件标识符,以防重放攻击。将 Webhook 签名密钥与发信凭据分开,并通过经过测试的流程进行轮换。设置请求大小限制,不要仅仅因为请求体能被解析,就信任其中的 URL、收件人、标签或事件字段。身份验证通过后,先持久化保存事件或将其放入队列,再返回成功。这样可以防止进程崩溃时丢失投递证据。Webhook 验证能够在已配置密钥的前提下证明请求的来源和完整性;但在应用将域名与服务商消息标识符关联起来之前,它并不能证明该业务事件属于预期的租户。

以幂等方式处理 Webhook 重试和重复事件

Mailgun 文档说明了当端点未返回预期的成功响应时的 Webhook 重试行为。接收端必须假设事件会延迟到达和重复投递。如果存在稳定的服务商事件标识符,就以其去重;否则使用一个保守的组合键,确保不会合并不同的收件人或事件类型。分别保留原始发生时间和处理时间。让状态转换单调推进,避免因重试乱序到达,较早的“已受理”或“已送达”观测结果覆盖掉之后的永久性失败、投诉或退订。只有在持久化保存之后才返回成功,但要让开销较大的业务处理异步进行,以保持端点可靠。监控签名失败、响应延迟、重试量、事件滞后和死信记录。原始服务商请求体只在运营和策略需要的期限内保留,并限制访问、尽量减少地址信息。Webhook 是一条证据来源,而不是跨租户暴露收件人历史的许可。

为 Mailgun 事件建模时不要夸大投递结果

Mailgun 文档列出了 accepted、delivered、暂时性和永久性失败、opened、clicked、unsubscribed、complained、stored 以及相关处理结果等事件类型。将这些名称映射到内部模型,同时保留服务商事件类型、消息标识符、收件人范围、时间戳、严重程度以及可用的 SMTP 响应。accepted 描述的是 Mailgun 的接收或排队进度。delivered 描述的是文档中定义的投递观测结果,通常是目标服务器已接收,但它并不能揭示邮件最终所在的邮箱文件夹。打开和点击属于互动指标,而不是传输证明,而且可能受到隐私技术的影响。暂时性失败可以在传输系统内部进行有上限的重试;永久性失败、投诉和退订则必须在提交任何后续应用任务之前更新收件人安全状态。让事件台账只追加不修改,并通过明确的规则推导出面向用户的状态,以便客服区分证据与解读。

在发送时执行失败、投诉和退订规则

Mailgun 文档介绍了对投递失败、垃圾邮件投诉和退订的跟踪。将这些信号导入产品自有的收件人安全模型,记录租户、地址、邮件类别、来源事件、原因和生效时间。在每次发送之前立即检查该状态,而不仅仅是在导入营销名单时检查。永久性退信或投诉应在适用范围内停止不安全的重试。退订处理必须遵守邮件类别以及收件方或法律的现行要求,不应通过服务商选项被常规性地绕过。任何手动移除操作都要受到严格授权保护,并附有可见的原因和审计历史。服务商的抑制数据是有价值的运营证据,但并不是完整的同意台账。请分别保存同意来源、偏好设置、产品关键策略决策和过往的服务商历史,以免迁移时丢失对收件人的保护。使用受控身份测试抑制状态的传播、重复投诉、延迟退信以及特殊情况下的重新启用。

将 SendHQ 视为 Mailgun 的替代方案

SendHQ 提供已验证域名发送、入站邮件、投递事件和抑制记录的事务性邮件与基于许可的营销邮件。迁移前,请查阅其公开 API 文档,并测试身份验证、请求体、错误、标识符、事件、域名和收件人安全工作流。

常见问题

通过 Mailgun API 发送邮件使用哪个端点?

Mailgun 文档说明了一个按域名划分的 `POST /v3/{domain}/messages` 端点,使用 multipart 表单数据和 HTTP Basic 身份验证。只能从经过授权的服务端代码调用它。

可以把 Mailgun API 密钥放在浏览器代码中吗?

不可以。将权限最小的合适凭据存放在服务端的密钥管理服务中。将生产环境、较低环境、账户管理、域名发信和 Webhook 签名的权限分开。

Mailgun API 受理是否意味着邮件已送达?

不是。它表示 Mailgun 已接受提交并进行处理。之后经过身份验证的事件可以报告目标服务器投递成功或失败,而进入收件箱仍是收件方一侧的独立结果。

应如何对 Mailgun Webhook 进行身份验证?

在处理之前,使用 Webhook 签名密钥校验 Mailgun 文档所述的 timestamp、token 和 signature。应用时效和防重放控制,然后在确认之前持久化保存事件。

每个 Mailgun API 失败都应该重试吗?

不应该。修正校验、身份验证、域名、权限和永久性策略错误。对符合条件的暂时性失败使用有上限的退避,并在重新发送之前对结果不确定的超时进行对账。

SendHQ 可以替代 Mailgun 吗?

可能可以。SendHQ 提供已验证域名发送、入站邮件、投递事件和抑制记录的事务性邮件与基于许可的营销邮件。迁移前,请查阅其公开 API 文档并测试您的集成。

参考来源