事件推送 Webhook
配置并验证邮件 Webhook,理解七类事件、签名、幂等和失败后的人工排查方式。
Webhook 用于把邮件事件主动推送到你的服务端,是获取每封邮件受理后结果(送达、退信、投诉、失败等)的主要途径。回调配置属于 API Key 级设置,当前由平台运营开通;客户控制台暂不提供 Webhook URL、事件订阅、签名密钥或投递日志的自助页面。
开通需要联系平台
接入 Webhook 前需联系平台运营,提供公网回调地址并确认事件订阅范围与签名模式。控制台暂不支持自助配置。
开始前的准备
提供公网 HTTPS 回调地址
回调地址必须使用 HTTPS 并具备有效证书。解析到内网、回环、链路本地或其他保留地址的域名会被拒绝。
确认事件类型与鉴权方式
与平台确认需要订阅的事件类型(见下文事件表),以及使用的签名模式:X-CALLBACK-ID 或兼容模式 X-Innomail-Signature。
保证接收接口 10 秒内返回 2xx
接收接口应在 10 秒内返回 2xx,不依赖重定向、Cookie 或自动重试。建议先持久化事件,再异步处理业务逻辑。
实现去重与对账
按 eventId 去重并持久化处理结果;按 Message ID 与控制台发送记录对账,确认最终投递状态。
可订阅事件
eventType | 含义 |
|---|---|
delivered | 收件方服务器确认接受邮件;不保证进入收件箱或已读。 |
bounced | 收到退信事件。 |
complained | 收到垃圾邮件投诉。 |
opened | 记录到打开事件;受追踪配置和客户端隐私行为影响。 |
clicked | 记录到链接点击事件。 |
delivery_delayed | 投递延迟,尚不是最终送达。 |
send_failed | 平台 Sender 形成确定的失败或拒绝结果。 |
打开和点击是否产生事件取决于发送通道及其追踪配置。send_failed 是邮件级事件,recipient 为空字符串。
请求格式
平台使用 POST 和 Content-Type: application/json 推送事件。通用请求头包括:
X-Innomail-Event:事件类型;X-Innomail-Event-Id:本次事件任务标识,与正文eventId对应。
正文示例:
{
"eventId": "EVENT-EXAMPLE-001",
"eventType": "delivered",
"messageId": "SINGLE-EXAMPLE-001",
"recipient": "alice@example.net",
"occurredAt": "2026-11-11T03:00:00Z",
"reasonCode": "",
"reasonMessage": ""
}所有字段按字符串处理。reasonCode 和 reasonMessage 可能为空;供应商事件与 Sender 失败事件使用不同的原因来源,不要把它们当作同一套码表。
验证回调签名
平台会为当前 API Key 配置以下一种模式。以平台开通时提供的模式和编码为准,不要输出或记录真实密钥。
X-CALLBACK-ID
请求头格式:
X-CALLBACK-ID: timestamp=<毫秒时间戳>;nonce=<随机值>;username=<用户名>;signature=<签名>计算方式:
signature = HMAC-SHA256(webhookSigningSecret, timestamp + nonce + username)三段直接拼接,无分隔符。默认输出小写十六进制,也可按平台配置使用 Base64。使用原始 timestamp、nonce 和 username 值重新计算并常量时间比较,同时检查时间戳有效性。
兼容模式:X-Innomail-Signature
当平台未配置独立 Webhook 用户名和签名密钥时,可能使用兼容模式:
signKey = HMAC-SHA256(apiSecret, "innomail-webhook-v1")
material = X-Innomail-Timestamp + "." + X-Innomail-Event-Id + "." + rawBody
X-Innomail-Signature = "sha256=" + lowercaseHex(HMAC-SHA256(signKey, material))rawBody 必须是收到的原始字节内容,不要先格式化 JSON。签名密钥是派生值,不是直接把 API Secret 当作消息 HMAC 密钥。
幂等与响应
- 以正文
eventId作为事件去重键,并持久化处理结果。 - 同一
messageId可以合法产生多个不同eventType,不要只用 Message ID 去重。 - 处理成功后再返回 2xx;如果先入库,可先持久化再异步处理。
事件不会自动重试或补发
平台当前对每个任务只投递一次。连接失败、超时和非 2xx 响应都不会自动重试或补发。请保证接收服务持续可用,并通过控制台发送记录定期对账;不要依赖“CB- 与 CBRT- 两类 ID 成对出现”等旧说明,也不要等待不存在的自动重推。
排查未收到事件
确认平台配置
与平台运营核对回调 URL 是否配置在正确的 API Key 上、启用状态和事件订阅范围。
检查网络与证书
核对公网 DNS 解析、HTTPS 证书有效性、解析地址可达性,以及 10 秒响应时限。
核对签名实现
检查签名模式、原始 Body、时间戳单位和十六进制/Base64 编码。
对照发送记录
在控制台发送记录中确认事件是否实际发生;打开和点击还需确认通道具备追踪能力。
联系平台排查
提供 Message ID、eventId、发生时间和你的接收日志。当前客户没有 Webhook 投递日志查询或人工补推入口。
Sender 失败原因码
详见Sender 失败原因码。
常见问题
为什么平台不自动重推事件?
当前每个事件任务只投递一次,连接失败、超时和非 2xx 都不会自动重试或补发。请保证接收服务可用,并以控制台发送记录对账为准;异常时联系平台运营,提供 Message ID 和 eventId 排查。
同一封邮件会收到多个事件吗?
会。同一 messageId 可以合法产生多个不同 eventType(例如先 delivery_delayed 后 delivered),应按 eventId 去重,而不是按 Message ID 去重。
签名校验一直失败怎么办?
按排查步骤检查签名模式、原始 Body、时间戳单位和编码格式。兼容模式下 rawBody 必须是收到的原始字节内容,不要先格式化 JSON;签名密钥是从 API Secret 派生的值,不是直接使用 API Secret。
send_failed 的原因码和供应商退信原因是什么关系?
send_failed 中的平台码 141001–141018 由平台定义;供应商回执的原始失败原因另行保留,两者不是同一套码表。
相关资源
最后更新于