
本文详解在 @aws-sdk/client-sns v3 中发送 sms 失败的常见原因——缺失区域配置与发信号码(originationnumber),并提供可立即生效的修复方案与最佳实践。
本文详解在 @aws-sdk/client-sns v3 中发送 sms 失败的常见原因——缺失区域配置与发信号码(originationnumber),并提供可立即生效的修复方案与最佳实践。
在将 AWS SDK 从 v2 升级到 v3 后,许多开发者发现 SNSClient.publish() 调用返回成功响应(HTTP 200 + MessageId),但目标手机号始终收不到短信。这并非网络或权限问题,而是 SDK v3 对配置的显式性要求更高:它不再自动推断区域(region),也不支持仅靠 PhoneNumber 和 Message 发送合规短信——尤其在启用 AWS Pinpoint 短信通道或启用了短信身份验证(SMS sandbox / origination number)的账户中。
✅ 关键修复点
1. 必须指定 region
AWS SNS 是区域化服务,v3 的 SNSClient 不会自动从凭证或环境变量推断 region。若未显式传入,客户端可能默认使用 us-east-1(即使你的资源部署在其他区域),导致请求被路由至错误区域而静默失败(或触发沙盒限制)。
✅ 正确做法:始终在 SNSClient 构造时传入明确的 region(如 'us-east-1'、'us-west-2' 等,需与你的 SNS 主题/短信配置所在区域一致):
const client = new SNSClient({
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
},
region: 'us-east-1' // ← 必填!确保与你的 SNS 配置区域一致
});2. 必须设置 OriginationNumber(发信号码)
自 AWS 强化短信合规策略后,直接向手机号发送短信(而非主题订阅)必须指定合法的发信方号码(即已验证/购买的电话号码或短代码)。该字段在 v2 SDK 中常被隐式处理,但在 v3 的 PublishCommand 输入中必须显式声明为 OriginationNumber(注意:不是 PhoneNumber):
const input = {
PhoneNumber: '+16045181234', // 接收方号码(含国家码)
Message: 'test message',
OriginationNumber: '+12065551234' // ← 必填!你已验证/购买的发信号码(需与账户绑定)
};⚠️ 注意:OriginationNumber 必须是已在 AWS Pinpoint 控制台 → SMS and voice → Phone numbers 中完成验证或购买的号码,且其所属区域需与 SNSClient.region 一致。
3. 权限策略建议优化
你当前的策略允许 sns:Publish 到任意资源("*"),虽功能可行,但不符合最小权限原则。推荐细化为:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sns:Publish",
"Resource": "arn:aws:sns:*:*:*" // 允许发布到本账户所有区域的 SNS 资源(更安全)
}
]
}✅ 完整修正后代码示例
import { PublishCommand, SNSClient } from '@aws-sdk/client-sns';
export const sendSms = async () => {
try {
const client = new SNSClient({
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!
},
region: 'us-east-1' // ← 显式指定区域(根据实际部署调整)
});
const input = {
PhoneNumber: '+16045181234',
Message: 'Hello from AWS SDK v3!',
OriginationNumber: '+12065551234' // ← 已验证的发信号码
};
const command = new PublishCommand(input);
const response = await client.send(command);
console.log('SMS sent successfully:', response.MessageId);
return response;
} catch (error: any) {
console.error('Failed to send SMS:', error.message);
throw error;
}
};? 排查补充提示
- ✅ 检查短信沙盒状态:新 AWS 账户默认处于 SMS sandbox,仅允许向已验证的手机号发送。请先在 SNS 控制台 → SMS → Phone numbers 中验证接收号码。
- ✅ 查看 CloudWatch Logs:启用 SNS 日志(需配置交付日志组),可捕获底层投递失败详情(如“Invalid phone number format”、“Throttling”等)。
- ✅ 使用 @aws-sdk/credential-providers(推荐):避免硬编码密钥,改用 fromEnv() 或 fromSSO() 等安全凭证链。
遵循以上配置,即可确保 @aws-sdk/client-sns v3 稳定、合规地发送 SMS。记住:显式优于隐式,区域与发信号缺一不可。

















