您可以通过消息队列接收短信发送状态报告(SmsReport)。此接口针对SendSms和SendBatchSms发送接口设置回执接收。
前提条件
已注册阿里云账号并生成访问密钥(AccessKey),详情请参见创建RAM用户的AccessKey。
确保可以在本地ping通以下地址:
dysmsapi.aliyuncs.com或mns.cn-hangzhou.aliyuncs.com或dybaseapi.aliyuncs.com。已阅读回执消息配置,了解回执消息模式、类型和配置流程。
SmsReport消息体格式
名称  | 类型  | 示例  | 描述  | 
send_time  | String  | 2021-09-06 15:49:55  | 转发给运营商的时间。  | 
report_time  | String  | 2021-09-06 15:49:58  | 收到运营商回执的时间。  | 
success  | Boolean  | true  | 是否发送成功。取值: 
  | 
err_msg  | String  | 用户接收成功  | 错误码信息描述。  | 
err_code  | String  | DELIVERED  | 错误码。  | 
phone_number  | String  | 159****6532  | 短信接收号码。  | 
sms_size  | String  | 1  | 短信长度。短信内容长度计算规则,请参见短信发送规则。  | 
biz_id  | String  | 12345  | 发送回执ID,即发送流水号。 调用发送接口SendSms或SendBatchSms发送短信时,返回值中的BizId字段。若批量发送短信时会有同一个BizId字段,可以查看批量发送记录。同一个阿里云账号下不同请求批次的BizId不同。 
  | 
out_id  | String  | 123456  | 调用发送短信SendSms接口时传的  | 
Demo下载
请参见轻量消息队列(原MNS)消费Demo,根据您需要的开发语言,完成Demo及SDK的下载。本文后续操作以Java语言为例。
Demo下载成功后,部分jar包在lib目录下,您需要单击Add as Library完成引入,具体如下图所示。
可在pom.xml文件中查找Maven依赖并安装阿里云Java SDK。

参数配置
使用该示例时,您需要先完成以下参数配置。
配置AccessKey
完整示例
您获取到的状态报告内容由dealMessage方法处理,您可以将需要的上行信息内容的业务逻辑写在该方法中。
// 根据文档中具体的消息格式进行消息体的解析
String arg = (String) contentMap.get("arg");
// 编写您的业务代码arg代表回执消息体中的参数,可填写的值为:send_time、report_time、success、err_msg、err_code、phone_number、sms_size、biz_id、out_id。
package com.alicom.mns.sample;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.alicom.mns.tools.DefaultAlicomMessagePuller;
import com.alicom.mns.tools.MessageListener;
import com.aliyun.mns.model.Message;
import com.google.gson.Gson;
/**
 * 只能用于接收云通信的消息,不能用于接收其他业务的消息
 */
public class ReceiveDemo {
    private static Log logger=LogFactory.getLog(ReceiveDemo.class);
    static class MyMessageListener implements MessageListener{
        private Gson gson=new Gson();
        @Override
        public boolean dealMessage(Message message) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //消息的几个关键值
            System.out.println("message receiver time from mns:" + format.format(new Date()));
            System.out.println("message handle: " + message.getReceiptHandle());
            System.out.println("message body: " + message.getMessageBodyAsString());
            System.out.println("message id: " + message.getMessageId());
            System.out.println("message dequeue count:" + message.getDequeueCount());
            System.out.println("Thread:" + Thread.currentThread().getName());
            try{
                Map<String,Object> contentMap=gson.fromJson(message.getMessageBodyAsString(), HashMap.class);
                // 根据文档中具体的消息格式进行消息体的解析
                String arg = (String) contentMap.get("arg");
                // 这里开始编写您的业务代码
            }catch(com.google.gson.JsonSyntaxException e){
                logger.error("error_json_format:"+message.getMessageBodyAsString(),e);
                //理论上不会出现格式错误的情况,所以遇见格式错误的消息,只能先delete,否则重新推送也会一直报错
                return true;
            } catch (Throwable e) {
                //您自己的代码部分导致的异常,应该return false,这样消息不会被delete掉,而会根据策略进行重推
                return false;
            }
            //消息处理成功,返回true, SDK将调用MNS的delete方法将消息从队列中删除掉
            return true;
        }
    }
    public static void main(String[] args) throws Exception, ParseException {
        DefaultAlicomMessagePuller puller=new DefaultAlicomMessagePuller();
        //设置异步线程池大小及任务队列的大小,还有无数据线程休眠时间
        puller.setConsumeMinThreadSize(6);
        puller.setConsumeMaxThreadSize(16);
        puller.setThreadQueueSize(200);
        puller.setPullMsgThreadSize(1);
        //和服务端联调问题时开启,平时无需开启,消耗性能
        puller.openDebugLog(false);
        // 从本地环境变量获取AccessKey ID和AccessKey Secret信息
        String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
        String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
        /*
        *  将messageType和queueName替换成您需要的消息类型名称和对应的队列名称
        *  云通信产品下所有的回执消息类型:
        *  1:短信回执:SmsReport,
        *  2:短信上行:SmsUp       
        *  3:国际短信回执:GlobeSmsReport
        */
        String messageType="<MESSAGE_TYPE>"; //此处应该替换成相应产品的消息类型
        String queueName="<QUEUE_NAME>"; //在云通信页面开通相应业务消息后,就能在页面上获得对应的queueName,格式类似Alicom-Queue-******-SmsUp
        puller.startReceiveMsg(accessKeyId,accessKeySecret,messageType,queueName,new MyMessageListener());
    }
}Demo运行后输出效果如下。

