做验证码、订单通知或营销触达时,很多开发者和运营同学都会卡在同一个地方:阿里云短信平台到底怎么用。流程看着不复杂,但签名审核、模板审核、权限配置任何一个环节出问题,上线时间就得往后挪。这篇按实际操作顺序,从开通讲到发出第一条短信,最后附一段可以直接改参数运行的代码。

一、开通前先确认三件事
动手之前,先把账号和需求理清楚。第一是阿里云账号要完成实名认证,个人和企业认证都可以用。不过企业主体提交的材料更完整,签名审核一般会更顺利,如果公司已经有认证主体,优先用它。第二是明确短信用途。验证码、通知类和营销类短信的审核标准差别很大,类型选错,模板很容易被驳回,返工一次就是几天。第三是提前准备签名材料,比如企业营业执照或网站备案信息,签名名称要和主体名称对得上。
举个例子。一个电商小团队要上线“注册验证码”和“订单发货通知”两类短信。他们在动手前就把两类短信的用途、触发时机和要展示的内容写成了一页纸。这样申请模板时,内容一次就能写到位,不用来回改。
二、开通服务并申请签名
登录阿里云控制台,进入“云通信”下面的“短信服务”页面,完成服务开通。接着在“国内消息”里找到“签名管理”,新增一个签名。签名一般是企业名称、品牌名或网站名,必须和申请主体保持一致,不能随便写一个听起来好看的名字。
提交后通常需要一到两个工作日审核。被驳回时,控制台会给出原因,常见的是签名和主体名称不一致,或者上传的材料不够清晰。改完可以直接重新提交,不需要重新开账号,也不用重新开通服务。
三、创建短信模板
签名过审之后,进入“模板管理”新建模板。模板里用变量占位,例如:您的验证码为${code},5分钟内有效,请勿泄露给他人。变量格式要严格按平台的要求来写,变量名只能用字母和数字,写成中文或带下划线的名字,提交时很可能直接报错。
模板审核被驳回,多半是下面三类问题:内容带有明显的营销语气、变量的用途说明不清楚、营销类模板缺少退订说明。验证码类模板越简单越好,除了验证码和有效期,不要再塞别的内容。上面这个写法就是一个比较稳妥的起点。
模板类型怎么选
- 验证码类:只放验证码和有效期,内容越少,审核通常越快。
- 通知类:用于订单、物流、账单这类事务提醒,内容要和业务状态直接对应,比如“您的订单已发货,单号为${orderNo}”。
- 营销类:用于活动推广,必须写明退订方式,还要注意平台对发送时段的限制,半夜发出去容易被投诉。
选类型时,拿不准的话就按最严格的标准准备材料。类型选低了,后面改成营销类重新审核,比一开始多写几行说明更麻烦。
四、获取凭证并安装 SDK
发送接口需要 AccessKey 鉴权,但不建议直接用主账号的 AccessKey。更稳妥的做法是在 RAM 控制台给短信发送单独建一个子用户,只授予短信相关的权限。这样即使密钥泄露,影响范围也有限。
凭证要放在环境变量或密钥管理服务里,不要写进代码,更不要提交到代码仓库。仓库一旦公开,密钥很快就会被扫描到并用来刷量。
以 Node.js 为例,安装官方 SDK:
npm install @alicloud/dysmsapi20170525 @alicloud/openapi-client @alicloud/tea-util
五、发送第一条短信
下面的代码从环境变量读取凭证,发送一条验证码短信。手机号、签名和模板编号都是占位值,换成自己账号里已经审核通过的内容就能跑。
const Dysmsapi20170525 = require('@alicloud/dysmsapi20170525');
const OpenApi = require('@alicloud/openapi-client');
const Util = require('@alicloud/tea-util');
function createClient() {
const config = new OpenApi.Config({
accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
endpoint: 'dysmsapi.aliyuncs.com'
});
return new Dysmsapi20170525.default(config);
}
async function sendCode(phone, code) {
const client = createClient();
const request = new Dysmsapi20170525.SendSmsRequest({
phoneNumbers: phone,
signName: '示例科技',
templateCode: 'SMS_000000000',
templateParam: JSON.stringify({ code })
});
const response = await client.sendSmsWithOptions(request, new Util.RuntimeOptions({}));
if (response.body.code !== 'OK') {
throw new Error('发送失败:' + response.body.message);
}
return response.body.bizId;
}
sendCode('13800000000', '123456')
.then(id => console.log('发送成功,回执ID:', id))
.catch(err => console.error(err.message));
这段代码有两个地方值得注意。第一是凭证来自环境变量,代码本身不含任何密钥。第二是返回结果要看业务码。短信接口即使返回业务错误,HTTP 请求本身也可能是成功的,如果只判断请求有没有报错,就会误以为短信已经发出去了。所以 response.body.code 必须校验,回执 ID 也建议存下来,方便日后对账。
六、发送失败时怎么排查
发送失败先看返回的错误码,通常能很快定位。isv.BUSINESS_LIMIT_CONTROL 一般说明触发了频率限制,同一个手机号短时间内发得太多,需要等一段时间再试。isv.MOBILE_NUMBER_ILLEGAL 是手机号格式不对,可以在发送前先用正则校验一遍。isv.TEMPLATE_MISSING_PARAMETERS 则是模板变量没有全部传入,对照模板里的变量名检查 templateParam 就行。
还有一类问题不在代码里,而是在业务设计上。验证码类短信如果没有限制,很容易被恶意刷量,每一条都要花钱。建议在业务层加上发送间隔,比如 60 秒内只能发一次,同时设置单个手机号和单个 IP 的每日上限。如果发送接口是公开的,还应该加上登录态或图形验证,否则刷接口的人可以不停地消耗你的短信额度。
七、收尾
整个流程可以归纳为五步:开通服务、申请签名、创建模板、配置凭证、调用接口。签名和模板前期多花一点时间写规范,后面改动就少很多。上面的代码可以作为起点,接入自己的业务逻辑后,再把错误处理和发送记录补完整就能上线。