短信模板被驳回,原因往往出在类型选错了,或者变量和业务事实对不上,文案好不好反倒是次要的。下面按申请、撰写、审核到调用的顺序,把阿里云短信模板的常见坑理一遍,并附上几个真实场景。

模板是什么,为什么审得这么细
阿里云短信服务要求国内短信使用预先报备的模板。模板是一段带占位符的固定文本,比如“您的验证码是${code},5分钟内有效”。发送时只传变量值,平台和运营商会核对内容是否与已通过的模板一致。
这套机制的出发点是减少垃圾短信和诈骗短信,同时便于追溯责任。所以审核员看的核心是这是不是一条正常的业务通知,文字漂不漂亮排在其次。理解这一点,改稿时的方向就清楚了。
三类模板,选错最容易被打回
控制台里的模板通常分为三类,各自的要求差别不小。
- 验证码类用于登录、注册、找回密码。内容要短,只放验证码和有效期,不要夹带其他信息。
- 通知类包括订单状态变更、物流提醒、预约成功这类。要能说清楚发生了什么事。
- 营销类包括促销、活动推广。审核最严,一般需要用户授权,并且要提供退订方式。
一家电商团队曾把“大促优惠券已到账”申报成通知类,正文里却没有订单或用户相关信息。审核员一看就判定为营销内容,要求改类型或重新提交。这类问题多半出在类型和内容对不上,文字本身未必违规。
撰写时注意的四点
容易过审的模板,通常有下面几个特点。
- 用途一眼可见。开头直接点明通知内容,例如“订单${orderNo}已发货”。
- 变量代表真实数据。变量应当是订单号、时间、课程名这类业务数据。如果把一整段推广文案塞进变量里,审核时很容易被拦下。
- 签名与主体一致。模板要配合已通过审核的签名使用。签名和业务主体对不上,发送会失败。
- 语气克制。“限时抢购”“速领”这类词放在非营销模板里,基本等于自找麻烦。
某在线教育平台最初的模板是“恭喜您获得限时好课推荐,点击链接立即报名${url}”。这条短信的推广意味很明显,被判为营销内容。后来改成“您预约的课程${courseName}将于${time}开课,请提前进入学习空间。”它描述的是一件已经发生的业务事件,审核顺利通过。两条文字的差别,基本就是审核员的判断依据。
申请与审核的基本步骤
- 先完成短信签名的审核。签名通常需要企业资质材料,这一步最好提前办,不然会卡住后面所有流程。
- 进入模板管理,选好类型,填写模板名称和内容。
- 提交后等待审核,时长从几小时到一两个工作日不等,以控制台提示为准。
- 通过后会得到模板CODE(形如SMS_xxxxxxx),调用接口时要用到它。
模板名称建议写具体一点,比如“订单发货通知-v1”,后期维护和版本迭代都方便。已通过的模板一旦修改,需要重新审核,所以上线前多花点时间打磨文案,能省下不少返工。
代码调用示例
下面是用阿里云 Java SDK(dysmsapi 包)发送模板短信的示例。
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.google.gson.Gson;
import java.util.Map;
public class SmsSender {
private final Client client;
public SmsSender(String accessKeyId, String accessKeySecret) throws Exception {
// 从环境变量或配置中心读取密钥,不要硬编码
Config config = new Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret)
.setEndpoint("dysmsapi.aliyuncs.com");
this.client = new Client(config);
}
/**
* 发送模板短信
* @param phone 手机号,国内号码不带国家码
* @param signName 已审核通过的短信签名
* @param templateCode 已审核通过的模板CODE
* @param params 模板变量,key 与模板中的 ${} 占位符对应
*/
public boolean send(String phone, String signName, String templateCode,
Map<String, String> params) throws Exception {
SendSmsRequest request = new SendSmsRequest()
.setPhoneNumbers(phone)
.setSignName(signName)
.setTemplateCode(templateCode)
.setTemplateParam(new Gson().toJson(params));
SendSmsResponse response = client.sendSms(request);
String code = response.getBody().getCode();
// 返回值 OK 表示提交成功,其他值需要记录日志并做重试或告警
if (!"OK".equals(code)) {
System.err.println("短信发送失败: " + response.getBody().getMessage());
return false;
}
return true;
}
}
调用时还有三件事要注意。
- AccessKey 从环境变量或密钥服务注入,不要写进代码仓库。短信功能最好单独建一个 RAM 子账号,只授予短信相关权限。
- 发送接口有频率限制。验证码请求要在业务层做限流,否则接口一旦被刷,费用和风险都会上来。
- 接口返回成功,只代表请求已提交,不代表用户已收到。最终送达情况要看回执查询。
上线后最容易出的三类问题
模板过审只是第一步,上线后还有几类问题要提前排查。
- 变量超长。变量内容超出模板允许的长度,发送会失败。昵称、地址这类动态字段,发送前要截断。
- 模板与参数不一致。代码里的参数名和模板占位符对不上,常见原因是模板改了,代码忘了同步。
- 国际短信套用国内规则。国际短信走不同通道,模板规则也不同,不能直接照搬国内模板。
还有一个案例。某团队上线后,部分用户收不到订单通知,但日志里接口一直返回成功。排查下来,问题出在模板新增了一个变量,代码却只传了旧参数。之后他们给参数加了校验,并对发送结果做了告警,同类问题就没再出现。
小结
阿里云短信模板的关键,是内容要贴合真实业务。类型选对,用途写清,变量只放业务数据,参数和模板保持同步,大部分驳回和故障都能避开。把模板内容和代码中的参数定义放在一起管理,每次修改都走审核和测试,后面迭代会省心很多。