编程 短信接口返回 OK 不等于送达:回执 DELIVRD 才算成功,72 小时没回执就是未知状态

2026-11-14 20:01:50

阿里云短信 Code=OK 不等于送达:回执报文、应答重试与签名报备排障

调用 SendSms 返回 Code=OK,只说明请求被短信平台接收,不代表短信已经送到用户手机。实际投递状态取决于运营商回执,而运营商回执又基于用户终端反馈。这条主线会贯穿后面的回执报文、状态码和排障顺序:平台侧成功、运营商侧成功、终端侧可见,是三件不同的事。

回执推送:SmsReport 报文结构

要收回执,先在控制台开启状态报告接收的 HTTP 批量推送模式,并配置接收地址。请求协议为 HTTP,格式 application/json,编码 UTF-8。

参数是 JSON Array,单次请求可能包含多个状态报告结果,不区分单发还是群发。字段如下:

  • phone_number:手机号
  • send_time:发送时间
  • report_time:状态报告时间
  • success:是否接收成功,true / false
  • err_code:状态报告编码
  • err_msg:状态报告说明
  • sms_size:短信长度
  • biz_id:发送回执 ID,即发送流水号,对应 SendSms 返回的 BizId,可用 QuerySendDetails 查具体状态
  • out_id:用户序列号

示例报文:

[{"phone_number":"1381111****","send_time":"2017-01-01 00:00:00","report_time":"2017-01-01 00:00:00","success":true,"err_code":"DELIVERED","err_msg":"用户接收成功","sms_size":"1","biz_id":"12345********","out_id":"67890**"}]

应答格式与重试规则

接收端必须返回:

{"code":0,"msg":"接收成功"}

系统只校验 code 是否为数字,不校验内容。HTTP 状态码 200 视为成功;非 200 或响应超时,系统会重试推送。若自身系统异常、消费失败,建议返回 50X。

重试规则很具体:第一次推送失败后重推 3 次,直至成功;3 次后仍失败则不再重试。也就是说,回调端不能依赖平台无限补推,落库和幂等要自己做。

回执配置不生效时先查这几处

  1. 每个阿里云账号仅支持配置一个回调地址,新配置会覆盖旧地址。
  2. HTTP 批量推送模式下,回调服务器要同时支持 GET 和 POST。GET 是阿里云用来校验连通性的,需在 700ms 内返回 {"code":0,"msg":"成功"},否则判为连通性校验失败。
  3. 使用 MNS 接收回执投递失败,可尝试关闭再重新开启上行消息功能,并保持地域为默认设置。
  4. 只发验证码且不需要回执时,可以不配 Callback。

PHP 接收回执示例

下面按文档报文写一个最小入口,同时处理 GET 连通性校验和 POST 回执。未在生产环境实测,接入前需按自己的框架补充鉴权、幂等和异常处理。

<?php
// 未在生产环境实测,按 SmsReport HTTP 批量推送文档编写
header('Content-Type: application/json; charset=utf-8');

if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    // 阿里云连通性校验,需在 700ms 内返回
    echo json_encode(['code' => 0, 'msg' => '成功']);
    exit;
}

$raw = file_get_contents('php://input');
$reports = json_decode($raw, true);

if (!is_array($reports)) {
    // 消费失败返回 50X,平台会重推
    http_response_code(500);
    echo json_encode(['code' => 500, 'msg' => 'bad payload']);
    exit;
}

foreach ($reports as $r) {
    $phone      = $r['phone_number'] ?? '';
    $success    = ($r['success'] === true);
    $errCode    = $r['err_code'] ?? '';
    $errMsg     = $r['err_msg'] ?? '';
    $bizId      = $r['biz_id'] ?? '';
    $outId      = $r['out_id'] ?? '';
    $sendTime   = $r['send_time'] ?? '';
    $reportTime = $r['report_time'] ?? '';

    // 以 biz_id 或 out_id 关联本地发送记录,做幂等更新
    // 注意:success=true 且 err_code=DELIVERED 才表示运营商侧送达
}

// 只校验 code 是否为数字;返回 0 表示接收成功
echo json_encode(['code' => 0, 'msg' => '接收成功']);

success 字段要和 err_code 一起看,不能只凭布尔值判断最终送达。

有解释力的回执状态码

文档里的错误码很多,排障时先认这几类:

  • REQUEST_SUCCESS:请求成功,平台接到请求,但未收到运营商侧回执状态,大概率是接收用户状态异常。
  • DELIVRD:成功。
  • UNDELIV:失败。
  • REJECTD:被 SMSC 驳回,例如用户已退订此签名或命中运营商平台黑名单规则。
  • EXPIRED:超时,含停机、关机等情况。
  • DELETED:短信被删除,终端问题。
  • SUBFALL / SUBFAIL:提交到网关失败。
  • MOBILE_TERMINAL_ERROR(文档中也写作 MOBLLE_TERMINAL_ERROR):手机终端问题、内存满、SIM 卡满、非法设备。
  • INVALID_NUMBER:号码状态异常,关机、停机、空号、暂停服务、不在服务区或格式错误。
  • CONTENT_KEYWORD:内容关键字拦截。
  • CONTENT_ERROR:内容无退订。推广短信必须带退订,如“拒收请回复R”。
  • SP_NOT_BY_INTER_SMS:收件人未开通国际短信。
  • SP_UNKNOWN_ERROR:运营商回执为未知错误。
  • USER_REJECT:接收用户已退订此业务。
  • BLACK / W-BLACK / 900 / 51401 等:黑名单,用户已退订此签名或命中运营商平台黑名单。

运营商侧还有几类高频原因:中国移动 DI:9413 表示 10 秒内同样内容同号码重复发送 2 次以上;DI:9402 是非法内容触发过滤规则;中国电信 99940 / 660650 / 99920 表示下发频率过快;MX:0003 是单个号码每天发送次数限制十条;中国联通 SGIP:88 / 89 是流控错误。

腾讯云回执码可做简短对照:DELIVRD 同为三网送达成功;-100520xxx 多为移动关键字拦截;-1044 是三网免打扰名单;-1033 是携号转网失败;-100 / -1017 / -19 对应空号、停机、关机。不同平台编码不同,但语义分层相似。

为什么“发送成功”但用户没收到

运营商回执基于短信网关的送达状态。短信已送达终端但被手机安全软件或系统垃圾短信过滤屏蔽时,运营商仍返回“发送成功”,平台无法感知终端侧拦截。只有当短信在运营商侧被拦截,比如内容关键字策略命中,才返回失败回执。

状态一直显示“发送中”,说明短信发出后久未收到运营商回执。72 小时内终端正常接收则更新为成功,否则更新为失败;超过 72 小时状态为“未知状态”。

批量全部失败:先查全局因素

按这个顺序查:

  1. 控制台查账户余额。
  2. 签名管理查看签名状态和运营商报备结果。签名“不可用”或报备结果为空,说明未完成实名制报备。
  3. 用该签名对移动、联通、电信号码分别少量多次发送,持续 5–7 个工作日触发自动补充报备。平均 5–7 个工作日,部分 7–10 个工作日。
  4. 控制台概览页开通验证码兜底方案,报备期间切换兜底签名。

签名必须符合“企事业单位名、已注册商标名”。存量签名使用其他来源会面临大量发送失败;新增签名审核通过后自动提交报备,存量签名需手动提交。

模板侧:模板审核状态须为通过且模板状态正常;模板内容不要含链接、联系方式等引流信息,运营商可能随机拦截,且无白名单保证 100% 送达;确认模板类型与签名适用场景匹配。

程序侧没有发送记录

先用 OpenAPI 调试门户以相同参数测 SendSms。调试成功而程序失败,问题在程序侧。检查 SignName、TemplateParam 传值格式、SDK 版本、本地日志与异常捕获。

网络连通看 ping dysmsapi.aliyuncs.com、telnet dysmsapi.aliyuncs.com 443。测试专用签名必须配测试模板,且只能发指定测试号码。

验证码与通知/推广的时效差别

验证码优先级最高,通常秒级送达;通知与推广不保证送达时效,受通道状态、内容审核影响。接入时不要用同一套超时和重试预期去覆盖两类业务。

文档

复制全文 生成海报 短信 接口对接 运维 PHP

推荐文章

程序员茄子在线接单