3.2 模板与签名:审核实操
场景:三审三驳的模板
接通 SMS 的第一周,我们信心满满提交了三份模板,结果两天内全部被驳:一个签名资质不全,一个正文里有敏感词,一个占位符顺序不对。审核驳回不会告诉你具体哪句话有问题,只给一句标准化的驳回理由,只能自己对照规则逐字排查。第三版才过审的时候,团队的结论是:模板审核不是技术活,是填表活加阅读理解。
最惨的一次是爽约告知模板。正文写的客客气气,审核员驳回理由是内容可能引起用户不适,我们集体盯着那句话看了半小时才反应过来,问题出在爽约这个词本身——平台担心短信里的负面词汇被运营商拦截,换个说法就好。从那以后我们把所有模板正文都用中性词重写了一遍,爽约叫未到访,违约金叫服务费,客人看到的语气没有变化,审核一帆风顺。
这一节把我们在驳回里滚出来的经验一次讲清楚:签名怎么选类型、正文怎么排版能过、占位符的顺序和顺序背后的逻辑、以及如何把审核周期从三天压到八小时。
审核这件事看似流程繁琐,其实站在平台的角度想就通了:短信通道是公共资源,一条违规短信可能导致整个签名被运营商拉黑,平台不敢赌。带着这个理解去看驳回理由,就不会觉得审核员在为难人,他们是在保护你。
方案:先签名后模板,两步走
签名和模板是两个独立审核的对象,先过签名再过模板,因为模板依赖于签名才能测试发送。签名是【】里的品牌名,模板是正文。签名审核看的是你有没有权用这个名字,模板审核看的是内容合不合规:
| 审核对象 | 审核重点 | 所需材料 | 我们的耗时 |
|---|---|---|---|
| 签名 | 名称所有权 | 营业执照、商标或公众号截图 | 约 2 小时 |
| 模板 | 内容合规 | 已审过的签名 | 约 2 到 8 小时 |
审核结果出来之前,控制台里的模板状态是审核中,这段时间可以先把后台的配置表建好,等编号一回来直接填进去,不耽误上线节奏。我们第一个版本因为等审核干等了两天,之后学乖了,所有模板相关代码都按编号可配置的方式写,审核与开发并行。
签名类型有四种,选错类型直接驳回。我们第一家门店用的是企业签名,后来加了小程序签名方便没有营业执照的分店走流程:
| 签名类型 | 适用 | 材料 |
|---|---|---|
| 企业签名 | 公司名或品牌 | 营业执照 |
| 小程序签名 | 小程序名称 | 小程序后台截图 |
| 公众号签名 | 公众号名称 | 公众号后台截图 |
| App 签名 | 应用商店上架名 | 应用商店截图 |
一个账号下可以共存多个签名,发送时在代码里指定用哪一个。三家门店共用一个企业签名是我们最初的做法,后来林姐希望每家店的短信抬头是自己的店名,于是又申请了两个小程序签名,配置表里按门店维度映射签名,发送时从订单上反查。
签名的有效期也值得留意。小程序签名要求对应小程序在近 30 天内有活跃使用记录,闲置超过几个月会被回收。我们有一家分店暂停营业两个月,签名被回收后客人收到提醒抬头变成了主品牌名,虽然没引起投诉,但林姐心里记了一笔。
签名回收这件事是运营在控制台手动发现的,告警并没有覆盖。后来我们把每月一次的签名状态巡检加进了值班清单,用脚本拉签名列表对照门店配置,状态一变就邮件通知。
配置:正文模板怎么写
我们的预约提醒模板最终过审的版本长这样(模板编号 1234568):
某某美甲提醒:您预约的{1}({2})将于{3}到店,地址:{4},到店请向店员出示预约码。退订回T。
四个变量依次是门店名、服务项目、时间、地址。看起来朴素,但每个字都有来头。正文模板有硬规则:不能出现繁体字、不能有特殊符号、不能出现股价汇率这类敏感词、不能有指向外部链接或二维码的引导。退订回T 这五个字是通知类模板建议带的,不加容易被驳。
最初的版本和过审版本差别很大,这里把淘汰过程也列一下,每一条驳回都对应一类硬规则:
| 版本 | 正文(节选) | 驳回原因 |
|---|---|---|
| V1 | 亲,您预约的服务已成功下单啦~ | 语气词过多,非正式 |
| V2 | 详情请点击 https://xxx.com | 含外链 |
| V3 | 门店地址:{1}(含 emoji) | 特殊符号 |
| V4 | 某某美甲提醒:您预约的{1}... | 通过 |
模板编号的管理方式我们踩过坑后改成了配置中心存储。最初模板编号硬编码在业务代码里,改一次模板要走一次代码发布,后来收敛到配置表,运营自己就能切:
| 模板用途 | 编号 | 状态 | 变量数 |
|---|---|---|---|
| 预约成功通知 | 1234567 | 已上线 | 4 |
| 到店前提醒 | 1234568 | 已上线 | 4 |
| 取消成功通知 | 1234569 | 已上线 | 2 |
| 爽约限约告知 | 1234570 | 审核中 | 2 |
配置表里还存了每条模板的负责人和上架日期,模板出问题的时候第一时间知道找谁。最早这四列只有编号两列,出过一次运营配错编号的事情——把取消通知的编号填到了提醒位,客人取消后反而收到一条到店提醒,电话打过来才算兜住。
代码:测试发送与自动校验
模板过审后先做一次测试发送。控制台提供测试手机号功能,输入手机号和参数值,秒级收到结果。我们把这一步固化进后端的一个内部接口,上线模板前调用一次:
func dryRunTpl(tplID string, params []string) error {
if len(params) != countTplVars(tplID) {
return errors.New("变量个数不匹配")
}
return SendSms(testPhone, tplID, params) // 发到备案测试号
}
变量个数不匹配是最常见的运行时错误。模板里四个 {N},代码传三个,接口报错且模板不会发送,客人那边静默丢失。校验函数上线后这类错误降到零。
测试号用的是我们自己的手机,一条测试短信几分钱,却能在上线前挡住所有参数类错误。建议每个模板过审后第一时间跑一次 dryRun,把真实收到的短信截图存档到模板文档里,作为这个模板长什么样的存证。
审核结果通过控制台查看,也有现状是审核驳回理由往往只有一句话。我们建了一份驳回词典文档,把自己遇到过的驳回原因和定位方法全记下来,新模板提交前先过一遍这份词典,审核周期从最初的三天缩短到平均八小时。
高流量模板的审核反而更快,这点出乎我们意料。月发送量大的账号似乎走了另一条审核通道,预约提醒模板第二次提交(改敏感词那次)两个半小时就过了。推测是平台对稳定发送账号的信任度更高,所以新账号初期最难,量起来之后会轻松很多。
踩坑:审核现场的四个坑
第一个坑是签名里的括号和空格。签名提交时写了全角括号,审核通过后发送时签名变成乱码,控制台显示正常但手机上呈现异常。重提交时只写品牌名本身,任何标点都不要。另外签名长度限制是八个字,超出会被截断提示,门店名过长时用简称。
第二个坑是变量顺序必须与代码传参顺序一致。模板里 {1} 是门店名,{2} 是项目,代码里如果先传项目后传门店,客人收到的短信就是您预约的(美甲)某某门店,逻辑上还成立,但时间字段挪到项目位置就成了一场误会,客人看到预约的(周六)某某美甲会直接懵掉。
这种错误不会报错,因为有变量个数校验把住了数量关,顺序校验平台不做。我们在 dryRun 里加了一层断言:按模板用途固定每个位置的语义,参数构造函数只暴露具名参数,从根上避免顺序颠倒。
顺带一个数字:变量顺序错误在上线第一个月出现了三次,都是从其他系统迁移历史预约时旧代码传参顺序没改干净。具名参数重构之后,三个月内零次。
第三个坑是敏感词不是常量。同一个模板在不同时期审核结果不同,有些词平时没问题、特殊时期就过不了。我们的爽约告知模板里有约束二字,某次提交被驳,改成提醒后通过。运营加了一条规矩:大改模板提交前先看一眼近期新闻。
第四个坑是一个模板里塞多种业务。最初图省事,预约成功和取消成功共用一个模板,正文里写满分支语,结果客人收到取消通知还得读两遍才分辨是成功还是取消。拆成两个模板后,每个都短了一半,条数计费反而更省。
另外还有一个小坑:模板提交后改不了。腾讯云的模板不支持编辑,只能重新提交新模板编号再替换,旧的废弃。所以提交前务必让林姐也看一眼正文,她常能看出客人读起来别扭的地方,这种往返一次就是两小时。
模板废弃后记得同步清理配置表,老编号残留等于一颗哑雷。我们有次回滚发布把取消通知指回了废弃编号,当天下午前台电话被打爆——短信发出去客人看到的还是旧版本文案,信息完全对不上。
小结
模板与签名的审核是整个短信接入里最没有技术含量却最耗耐心的环节。记住三句话:签名选对类型、模板只说一件事、变量顺序对齐。八小时过审和三天过审的差别,全在提交前的那一遍自查。驳回词典文档如今是团队新人入职必读,比任何官方文档都好使。下一节看怎么用免费的订阅消息把日常提醒成本压到零。
延伸阅读
- 短信接入的完整链路,翻 短信接入:腾讯云 SMS
- 免费通道的实现,见 订阅消息:小程序内通知
- 触达率的数据复盘,见 触达策略:多通道兜底
- Go 后端的工程实践,见 Go 微服务实战
- 另一套消息触达的工程化做法,翻 Go IM 实战
