一、提交成功与送达成功不是同一件事
调用短信API时获得HTTP 200或平台返回message ID,通常只说明请求格式正确并被平台接收。之后短信还要经过平台队列、通道路由、运营商网络和用户设备,任何阶段都可能出现失败或延迟。
因此企业需要分别保存“API提交结果”和“最终送达状态”。只用接口成功数计算送达率,会高估实际效果,也无法解释用户没有收到验证码或通知的原因。
二、典型状态生命周期
| 统一状态 | 含义 | 是否最终状态 |
|---|---|---|
| submitted | 企业请求已提交 | 否 |
| accepted | 平台已接收并准备路由 | 否 |
| sent | 消息已交给下游通道或运营商 | 否 |
| delivered | 运营商报告已送达设备 | 通常是 |
| failed | 发送失败并返回失败原因 | 通常是 |
| expired | 在有效时间内未完成发送 | 是 |
| rejected | 因规则、内容或权限被拒绝 | 是 |
| unknown | 暂时无法确定最终结果 | 视平台规则 |
不同平台使用的状态名称可能不同。企业应在接入层把供应商状态映射为自己的统一状态,业务系统不要直接依赖某一家供应商的专有字段。
三、状态映射的设计原则
状态映射不仅要保存统一结果,还应保留原始状态、原始错误码和原始回执内容。这样既方便业务使用统一报表,也能在出现争议时追查供应商返回的具体信息。
{
"message_id": "msg_01J...",
"business_id": "login_20260716_001",
"provider_status": "DELIVRD",
"normalized_status": "delivered",
"error_code": null,
"occurred_at": "2026-07-16T06:40:12Z"
}
映射表需要版本管理。当供应商增加状态或修改含义时,应先更新映射测试,再投入生产,避免未知状态被错误归类为成功。
四、通过Webhook处理回执
Webhook适合实时接收状态。处理流程包括验签、事件去重、message ID关联、状态顺序判断、数据库更新和业务通知。对于重复回调,应利用事件ID或“message ID+状态+时间”进行幂等处理。
如果企业暂时没有Webhook能力,也可以使用查询接口补充状态,但不应高频轮询。较稳妥的方案是Webhook为主、定期对账查询为辅,以发现遗漏回调或系统故障。
五、建议保存哪些字段?
| 字段 | 用途 |
|---|---|
| business_id | 关联订单、验证码、通知或活动任务 |
| message_id | 关联短信平台记录 |
| destination | 目标号码,展示时应掩码 |
| submitted_at | 计算排队和提交耗时 |
| sent_at / delivered_at | 计算端到端延迟 |
| normalized_status | 供业务和报表统一使用 |
| provider_status / error_code | 用于技术排查和供应商对账 |
| route / country / carrier | 按国家和运营商分析质量 |
六、如何使用回执分析质量?
送达率应使用最终delivered数量除以具备最终结果的有效提交量,同时单独观察pending和unknown比例。验证码业务还应分析提交到送达的p50、p95和p99延迟,以及用户验证成功率。
不能只看全站平均值。某个国家或运营商可能明显异常,但会被其他高成功率市场掩盖。
七、回执异常与对账
- 定期查询长时间处于pending的消息。
- 对比平台报表、Webhook记录和企业数据库。
- 检查回调端点是否出现超时、非2xx和积压。
- 未知错误码应进入待分析列表,而不是直接归为失败。
- 为OTP、通知和营销流量分别统计送达率。
- 对失败率和状态延迟突然上升设置告警。