1-Python - 短信服务
- about
- 容联云短信
- 互亿无线106短信
- 腾讯云短信
- SDK方式发送短信
- api形式实现短信发送
- 常见报错
- tencentcloud.common.exception.tencent_cloud_sdk_exception.TencentCloudSDKException: [TencentCloudSDKException] code:ClientNetworkError message:HTTPSConnectionPool(host='sms.tencentcloudapi.com', port=443): Max retries exceeded with url: / (Caused by ProxyError('Cannot connect to proxy.', timeout('_ssl.c:1114: The handshake operation timed out'))) requestId:None
("SendstatusSet": [{"Seriao": "n, "phonenumben": "+8618211101111", "Fee": 0, "SessionContext": "n, "Code": "FailedOperation.InsufficientBalanceInSmsPackage", "Message": "insufficient balance in SMS package", "IsoCode": mny], "RequestId".85e31f2c-9507-49c3-a288-7ed741afbf16"}
- tencentcloud.common.exception.tencent_cloud_sdk_exception.TencentCloudSDKException: [TencentCloudSDKException] code:UnauthorizedOperation.SmsSdkAppIdVerifyFail message:request SmsSdk AppId verify fail requestId:6e63e34e-fa46-40ee-9281-320446e80c1a
- 腾讯短信发送成功,但手机接收不到短信
about
在项目中集成短信功能,如短信验证登录、发送短信通知,现在非常普遍,所以本篇记录下如何在项目中集成短信功能。
由于监管严格,有的短信服务商开通短信服务的资质也越来越严格,导致我们在开发阶段,不得不尝试其它更多厂家的,目前(2023/5/16)据我了解,不确认以后会不会放开个人资质认证:
- 腾讯云,现在开通短信服务要么你要有公司资质、要么是已经上线并且备案的小程序这些,所以开通门槛有点高了。
- 容联云,之前还支持个人认证,目前(2023/5/24)只支持公司认证了,不支持个人认证,但它提供了一个测试号码,也就是我们开发阶段使用这个测试号码也是可以的。
- 互亿无线的106短信,这个今天我测了下,现在还能支持个人认证,总之开通和认证都简单、代码也不难,配置也相对简单,如果是个人项目开发阶段,用这个也行。
容联云短信
这里演示下如何开通容联云的短信测试账号,保证我们开发阶段的短信服务正常使用。
配置过程
1. 注册,没啥好说的了,注册地址:https://console.yuntongxun.com/user/reg/init
2. 注册成功,在控制台首页(https://console.yuntongxun.com/member/main),就能获取到以下信息
3. 添加测试号码,这就是未通过认证,我们只能在开发中,在这里添加最多3个测试号码来进行开发中使用
4. 短信模板
短信模板这块,由于是测试使用,我们只能使用固定的短信模板了,我写这部分博客时,发出的短信长这样:
【云通讯】您使用的是云通讯短信模板,您的验证码是4653,请于2分钟内正确输入(变量仅支持1-4位数字)
要想更换短信模板,就要充钱了.....所以,我们还是凑活用吧,上线了再改一样。
所以,这里我们能知道的就是一个模板ID为1
,这个后面发短信要用到,记好了。
5. 发送短信示例
各语言参考手册:
来个Python的示例,先下载对应的模块:
pip install ronglian_sms_sdk
然后来上demo示例,当然这个示例完全可以集成到你的项目中:
import random
import json
from ronglian_sms_sdk import SmsSDK
def send_sms(mobile, datas, tid=1):
"""
发送短信
@params tid: 模板ID,默认测试使用1
@params mobile: 接收短信的手机号,多个手机号使用都逗号隔开
单个号码: mobile="13312345678"
多个号码: mobile="13312345678,13312345679,...."
@params datas: 短信模板的参数列表
例如短信模板为: 【云通讯】您的验证码是{1},请于{2}分钟内正确输入。
则datas=("3456",2,)
最终发送的短信为:【云通讯】您的验证码是{3456},请于{5}分钟内正确输入。
"""
RONGLIANYUN_CONFIG = {
# 下面这三个值都可以从控制台首页的开发者主账号中进行获取
"accId": '2c94811c87fb71111881e50a8ed0b39', # 对应:ACCOUNT SID
"accToken": '23d2e5f9f7111e888eb2a6848dae42', # 对应:AUTH TOKEN
"appId": '2c94811c87fb11101881e50aa210b40', # 对应:AppID(默认)
"reg_tid": 1, # 注册短信验证码的模板ID,测试阶段固定为1
"sms_expire": 120, # 短信有效期,单位:秒(s),这是真正的超时时间,注意和datas=("3456",2,)中第二个参数进行换算,保持一致
"sms_interval": 60, # 短信发送的冷却时间,单位:秒(s)
}
sdk = SmsSDK(RONGLIANYUN_CONFIG.get("accId"), RONGLIANYUN_CONFIG.get("accToken"), RONGLIANYUN_CONFIG.get("appId"))
resp = sdk.sendMessage(str(tid), mobile, datas)
response = json.loads(resp)
print(response, type(response))
"""
Sign plaintext: 2c94811c87fb7ec601881e50a8ed0b3923d2e5f9f7694d9e888eb2a6848dae4220230524140059
Authorization plaintext: 2c94811c87fb7ec601881e50a8ed0b39:20230524140059
Request url: https://app.cloopen.com:8883/2013-12-26/Accounts/2c94811c87fb7ec601881e50a8ed0b39/SMS/TemplateSMS?sig=6FB880CDC9671A41674C17DE348D300B
Request headers: {'Content-Type': 'application/json;charset=utf-8', 'Accept': 'application/json', 'Accept-Charset': 'UTF-8', 'Authorization': b'MmM5NDgxMWM4N2ZiN2VjNjAxODgxZTUwYThlZDBiMzk6MjAyMzA1MjQxNDAwNTk='}
Request body: {"to": "18211101742", "appId": "2c94811c87fb7ec601881e50aa210b40", "templateId": "1", "datas": [4653, 2]}
Response body: {"statusCode":"000000","templateSMS":{"smsMessageSid":"8bcc77c455084a6b8d52983e95f10977","dateCreated":"20230524140100"}}
{'statusCode': '000000', 'templateSMS': {'smsMessageSid': '8bcc77c455084a6b8d52983e95f10977', 'dateCreated': '20230524140100'}} <class 'dict'>
"""
# statusCode是'000000'表示发送成功
# 手机上接收到的短信长这样
"""
【云通讯】您使用的是云通讯短信模板,您的验证码是4653,请于2分钟内正确输入(变量仅支持1-4位数字)
"""
return response.get("statusCode") == "000000"
def get_code(num=4):
"""
生成指定位数的验证码,如果不传值,就默认生成4位的验证码
:param num: 要生成几位的验证码
:return: 生成的验证码
"""
return random.randint(
int('1{}'.format('0' * (num - 1))),
int('9{}'.format('9' * (num - 1)))
)
if __name__ == '__main__':
send_sms(
mobile='18211101111', # 这个手机号必须在你在容联云中填写的那个3个测试手机号中
datas=(get_code(4), 2), # 元组的第一个参数是4位的验证码,注意免费测试的只支持发送4位的验证码,不支持6位的,第二个参数是短信模板中替换为:请于{2}分钟内正确输入
tid=1 # 这个模板id目前测试阶段固定为1
)
常见报错
{'statusCode': '161125', 'statusMsg': '请输入1到4位的数字'}
这个报错很明显是规定只能发送4位的验证码,你却发送了6的验证码,所以报错了,解决办法就是生成4位验证码即可。
互亿无线106短信
PS:注册后,互亿无线的客服会给你打电话问一下使用用途,说个人项目开发中使用即可,好用的话,会在公司中推荐正式使用的。
然后跟着我下面的流程走就行了,非常简单。
注册及认证
1. 实名注册:https://user.ihuyi.com/new/register.html?e=400
2. 注册成功后,会自动跳转到控制台,没自动跳转就手动点击网址:https://user.ihuyi.com/new/console
3. 点击认证,这里进行个人认证,然后按照下图提示在手机上进行微信认证。
4. 手机上进行微信认证,按照微信中的引导即可。
5. 浏览器中回到控制台的账号信息页面,发现认证通过了。https://user.ihuyi.com/new/console/account/infomation?jumpto=certify
现在认证完事了。
发送短信验证码基础版
当你注册认证通过之后,会得到10条免费短信,也会有个默认的短信模板(充值之后可以创建自定义模板)。
我们可以尝试使用默认的模板和免费短信来写个demo示例,示例中还需要两个参数需要我们提前准备好。
#定义请求的数据
values = {
'account': 'C05062023', # 这个是对应的APIID
'password': 'aff16e275e46618efd14f21b00ad12391', # 这个是对应的APIKEY
'mobile': mobile, # 你要发给谁
'content': '您的验证码是:7835。请不要把验证码泄露给其他人。', # 没有购买套餐的,这个模板只能使用默认的,即你收到的短信长这样:【互亿无线】您的验证码是:7835。请不要把验证码泄露给其他人。
'format': 'json',
}
上面请求参数中,我们需要准备的是APIID
和APIKEY
,这俩在如下图所示的位置可以找到:https://user.ihuyi.com/new/sms/overview
下面的示例是基于Python3的示例:
#python3
#接口类型:互亿无线触发短信接口,支持发送验证码短信、订单通知短信等。
#账户注册:请通过该地址开通账户https://user.ihuyi.com/new/register.html
#注意事项:
#(1)调试期间,请用默认的模板进行测试,默认模板详见接口文档;
#(2)请使用 用户名 及 APIkey来调用接口,APIkey在会员中心可以获取;
#(3)该代码仅供接入互亿无线短信接口参考使用,客户可根据实际需要自行编写;
import random
import urllib.parse
import urllib.request
def get_code(num=4):
"""
生成指定位数的验证码,如果不传值,就默认生成4位的验证码
:param num: 要生成几位的验证码
:return: 生成的验证码
"""
return random.randint(
int('1{}'.format('0' * (num - 1))),
int('9{}'.format('9' * (num - 1)))
)
def send_sms(mobile, code_num=4):
"""
发送短信验证码
:param mobile: 你要发给谁
:param code_num: 发送几位的验证码
:return:
"""
# 接口地址,咱们不需要更改
url = 'http://106.ihuyi.com/webservice/sms.php?method=Submit'
# 定义请求的数据
values = {
'account': 'APIID', # 这个是对应的APIID
'password': 'APIKEY', # 这个是对应的APIKEY
'mobile': mobile, # 发给谁
'content': '您的验证码是:{}。请不要把验证码泄露给其他人。'.format(get_code()), # 没有购买套餐的,这个模板只能使用默认的,即你收到的短信长这样:【互亿无线】您的验证码是:7835。请不要把验证码泄露给其他人。
'format': 'json', # 不要动
}
# 将数据进行编码,下面代码不要动
data = urllib.parse.urlencode(values).encode(encoding='UTF8')
# 发起请求,下面代码不要动
req = urllib.request.Request(url, data)
response = urllib.request.urlopen(req)
res = response.read()
# 打印结果,然后你的手机应该就能接到短信了
print(res.decode("utf8")) # {"code":2,"msg":"提交成功","smsid":"16842079209571524017"}
if __name__ == '__main__':
send_sms('接收短信的手机号')
腾讯云短信
python3.9
腾讯云短信服务官网:https://cloud.tencent.com/product/sms
腾讯云短信文档: https://cloud.tencent.com/document/product/382
具体的注册流程参考:https://pythonav.com/wiki/detail/10/81/
SDK方式发送短信
python3.9
短信模板:https://console.cloud.tencent.com/smsv2/csms-template
签名信息:https://console.cloud.tencent.com/smsv2/csms-sign
应用 ID:https://console.cloud.tencent.com/smsv2/app-manage
API密钥:https://console.cloud.tencent.com/cam/capi
前提(截止到2023/2/6):
- 依赖环境:Python 2.7, 3.6-3.9 版本,来自Gitee,你也可以从GitHub仓库查看。
- 应该提前创建好应用,并获取应用ID。
- 提前准备好秘钥,用于获取SecretId和SecretKey:
- 提前准备好签名,这一步有点麻烦,因为需要审核。
- 提前准备好模板,比如
| 验证码为:{1},您正在登录,若非本人操作,请勿泄露。
其中的{1}
就是我们将来要自定义
下载相应的SDK
通过pip下载SDK:
# 国内如果能访问GitHub的话可以通过这个命令下载,否则用下面的Gitee的也行
pip install --upgrade tencentcloud-sdk-python
# Gitee
pip install --upgrade tencentcloud-sdk-python
发送短信代码示例
请无脑的参考下面的流程就行了,让你去哪找就去哪找,让你改啥你就改啥,不让你改啥,别瞎动。
import random
import string
from tencentcloud.common import credential
from tencentcloud.sms.v20210111 import sms_client, models
# 注意,下面写法是固定的,你只需要按照上面给的链接中,获取对应的值,来修改即可
# 下面这俩值从这个页面中获取:https://console.cloud.tencent.com/cam/capi
SecretId = "AKIDQdZFemCGdlcCo9sQ9sKkwriIq776rUu423"
SecretKey = "FEvLZWBZgX7JFzRcW8VbgU7UZOvCuc3123"
cred = credential.Credential(
secret_id=SecretId, # 注意必须以关键字的形式传参
secret_key=SecretKey # 注意必须以关键字的形式传参
) # secretId secretKey
client = sms_client.SmsClient(cred, "ap-guangzhou") # 固定写法无需变动
req = models.SendSmsRequest()
# 应用id,注意这个是你创建的应用id,是这个链接:https://console.cloud.tencent.com/smsv2/app-manage 中的应用ID
# 强调,不是密钥页面的APPID,既不是这个页面的ID:https://console.cloud.tencent.com/cam/capi
req.SmsSdkAppId = "1400793123"
# 模板签名:https://console.cloud.tencent.com/smsv2/csms-sign 也就是签名管理菜单中,找到你的签名内容
req.SignName = "张开与老虎" # 模板签名
# 模板id从这个地址找:https://console.cloud.tencent.com/smsv2/csms-template, 也就是正文模板管理菜单
req.TemplateId = "5750123" # 模板id(可以有多套模板进行更换,这样发送的短信内容就可以改变了)
# 下面就是结合模板填写具体要发送的验证码和手机号了
code = ''.join(random.sample(string.digits, 6)) # 随机生成的6位验证码
print(code) # 671093
# 如果短信模板中只有一个值需要填充,那么列表中就放一个值就好了,注意,数字的话,必须是转成字符串类型。
req.TemplateParamSet = [code] # 发送的6位验证码
# 如果你要发送的短信模板是这样的(您正在申请手机注册,验证码为:{1},[2}分钟内有效!),有多个值需要填充,就依次填写到列表中就好了,注意,数字的话,必须是转成字符串类型。
# req.TemplateParamSet = [code, '5'] # 发送的6位验证码
req.PhoneNumberSet = ["+8618211111111"] # 目标手机号
resp = client.SendSms(req) # 发送
print(resp)
"""
{
"SendStatusSet": [
{
"SerialNo": "2433:326237685316756579077330174",
"PhoneNumber": "+8618211101111",
"Fee": 1, "SessionContext": "",
"Code": "Ok", "Message": "send success", "IsoCode": "CN"
}
],
"RequestId": "25147cb8-9abd-4100-bdbb-bb61cd3c2828"
}
# 你的手机号,应该接收到了短信:
【张开与老虎】验证码为:671093,您正在登录,若非本人操作,请勿泄露。
"""
更详细的示例参考官网:https://cloud.tencent.com/document/product/382/43196
错误码:https://cloud.tencent.com/document/product/382/38780
api形式实现短信发送
python3.9
常见报错
tencentcloud.common.exception.tencent_cloud_sdk_exception.TencentCloudSDKException: [TencentCloudSDKException] code:ClientNetworkError message:HTTPSConnectionPool(host='sms.tencentcloudapi.com', port=443): Max retries exceeded with url: / (Caused by ProxyError('Cannot connect to proxy.', timeout('_ssl.c:1114: The handshake operation timed out'))) requestId:None
如果你发短信的代码运行后,等了一段时间,然后报了超时的错误,而你又能正常的上网,那么优先检查你的电脑是否开着代理,有代理,短信服务就不可用。
tencentcloud.common.exception.tencent_cloud_sdk_exception.TencentCloudSDKException: [TencentCloudSDKException] code:ClientNetworkError message:HTTPSConnectionPool(host='sms.tencentcloudapi.com', port=443): Max retries exceeded with url: / (Caused by ProxyError('Cannot connect to proxy.', timeout('_ssl.c:1114: The handshake operation timed out'))) requestId:None
关闭代理再重发,就应该没问题了。
("SendstatusSet": [{"Seriao": "n, "phonenumben": "+8618211101111", "Fee": 0, "SessionContext": "n, "Code": "FailedOperation.InsufficientBalanceInSmsPackage", "Message": "insufficient balance in SMS package", "IsoCode": mny], "RequestId".85e31f2c-9507-49c3-a288-7ed741afbf16"}
这个错误根据官网的错误码,说是套餐包余量不足,需要充值了。
- 错误码:https://cloud.tencent.com/document/product/382/38780,下拉页面找到业务错误码,部分,就有了
FailedOperation.InsufficientBalanceInSmsPackage
报错。 - 充值:https://buy.cloud.tencent.com/sms
tencentcloud.common.exception.tencent_cloud_sdk_exception.TencentCloudSDKException: [TencentCloudSDKException] code:UnauthorizedOperation.SmsSdkAppIdVerifyFail message:request SmsSdk AppId verify fail requestId:6e63e34e-fa46-40ee-9281-320446e80c1a
这个报错没啥好说的,就是req.SmsSdkAppId
的值获取错了,应该获取的是应用ID。
当然也要检查其他的参数是否填写正确。
腾讯短信发送成功,但手机接收不到短信
按照上面腾讯云短信的示例,发送短信成功了,打印结果也是:
{"SendStatusSet": [{"SerialNo": "2640:63003780816991009901530174", "PhoneNumber": "+8618211101742", "Fee": 1, "SessionContext": "", "Code": "Ok", "Message": "send success", "IsoCode": "CN"}], "RequestId": "959d08ca-9af8-4974-ab82-307a4dcee0a0"}
看发送结果肯定是没问题的,但是手机就是收不到消息,去腾讯云官档查统计分析记录,发现,被运营商拦截了:
解决办法就是腾讯云的人工服务吧。