├── .gitignore
├── LICENSE
├── MANIFEST.in
├── README
├── README.md
├── docs
├── httpclient.m.html
├── index.html
├── sms.m.html
├── util.m.html
└── voice.m.html
├── gendoc.py
├── qcloudsms_py
├── __init__.py
├── httpclient.py
├── sms.py
├── util.py
└── voice.py
└── setup.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.pyo
3 | *.so
4 | *.class
5 | *~
6 | *.egg-info/
7 | build/
8 | dist/
9 | test.py
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 qcloudsms
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | recursive-include qcloudsms_py *.py
2 | recursive-include docs *
3 | prune docs/build
4 | include LICENSE
5 | include README
6 | include gendoc.py
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | 腾讯云短信 Python SDK
2 | ===
3 |
4 | ## 腾讯短信服务
5 |
6 | 目前`腾讯云短信`为客户提供`国内短信`、`国内语音`和`海外短信`三大服务,腾讯云短信SDK支持以下操作:
7 |
8 | ### 国内短信
9 |
10 | 国内短信支持操作:
11 |
12 | - 指定模板单发短信
13 | - 指定模板群发短信
14 | - 拉取短信回执和短信回复状态
15 |
16 | > `Note` 短信拉取功能需要联系腾讯云短信技术支持(QQ:3012203387)开通权限,量大客户可以使用此功能批量拉取,其他客户不建议使用。
17 |
18 | ### 海外短信
19 |
20 | 海外短信支持操作:
21 |
22 | - 指定模板单发短信
23 | - 指定模板群发短信
24 | - 拉取短信回执和短信回复状态
25 |
26 | > `Note` 海外短信和国内短信使用同一接口,只需替换相应的国家码与手机号码,每次请求群发接口手机号码需全部为国内或者海外手机号码。
27 |
28 | ### 语音通知
29 |
30 | 语音通知支持操作:
31 |
32 | - 发送语音验证码
33 | - 发送语音通知
34 | - 上传语音文件
35 | - 按语音文件fid发送语音通知
36 | - 指定模板发送语音通知类
37 |
38 | ## 开发
39 |
40 | ### 准备
41 |
42 | 在开始开发云短信应用之前,需要准备如下信息:
43 |
44 | - [x] 获取SDK AppID和AppKey
45 |
46 | 云短信应用SDK `AppID`和`AppKey`可在[短信控制台](https://console.cloud.tencent.com/sms)的应用信息里获取,如您尚未添加应用,请到[短信控制台](https://console.cloud.tencent.com/sms)中添加应用。
47 |
48 | - [x] 申请签名
49 |
50 | 一个完整的短信由短信`签名`和短信正文内容两部分组成,短信`签名`须申请和审核,`签名`可在[短信控制台](https://console.cloud.tencent.com/sms)的相应服务模块`内容配置`中进行申请。
51 |
52 | - [x] 申请模板
53 |
54 | 同样短信或语音正文内容`模板`须申请和审核,`模板`可在[短信控制台](https://console.cloud.tencent.com/sms)的相应服务模块`内容配置`中进行申请。
55 |
56 | ### 安装
57 |
58 | #### pip
59 |
60 | qcloudsms_py采用pip进行安装,要使用qcloudsms功能, 只需要执行:
61 |
62 | ```shell
63 | pip install qcloudsms_py
64 | ```
65 |
66 | #### 手动
67 |
68 | 1. 手动下载或clone最新版本qcloudsms_py代码
69 | 2. 在qcloudsms_py目录运行 `python setup.py install`或直接把qcloudsms_py所在目录加入`sys.path`
70 |
71 | > `Note` python2/python3都支持
72 |
73 | ### 文档
74 |
75 | 若您对接口存在疑问,可以查阅:
76 |
77 | * [API开发指南](https://cloud.tencent.com/document/product/382/5808)
78 | * [SDK文档](https://qcloudsms.github.io/qcloudsms_py/)
79 | * [错误码](https://cloud.tencent.com/document/product/382/3771)
80 |
81 | ### 示例
82 |
83 | - **准备必要参数**
84 |
85 | ```python
86 | # 短信应用SDK AppID
87 | appid = 1400009099 # SDK AppID是1400开头
88 |
89 | # 短信应用SDK AppKey
90 | appkey = "9ff91d87c2cd7cd0ea762f141975d1df37481d48700d70ac37470aefc60f9bad"
91 |
92 | # 需要发送短信的手机号码
93 | phone_numbers = ["21212313123", "12345678902", "12345678903"]
94 |
95 | # 短信模板ID,需要在短信应用中申请
96 | template_id = 7839 # NOTE: 这里的模板ID`7839`只是一个示例,真实的模板ID需要在短信控制台中申请
97 |
98 | # 签名
99 | sms_sign = "腾讯云" # NOTE: 这里的签名"腾讯云"只是一个示例,真实的签名需要在短信控制台中申请,另外签名参数使用的是`签名内容`,而不是`签名ID`
100 | ```
101 |
102 | - **指定模板ID单发短信**
103 |
104 | ```python
105 | from qcloudsms_py import SmsSingleSender
106 | from qcloudsms_py.httpclient import HTTPError
107 |
108 | ssender = SmsSingleSender(appid, appkey)
109 | params = ["5678"] # 当模板没有参数时,`params = []`
110 | try:
111 | result = ssender.send_with_param(86, phone_numbers[0],
112 | template_id, params, sign=sms_sign, extend="", ext="") # 签名参数不允许为空串
113 | except HTTPError as e:
114 | print(e)
115 | except Exception as e:
116 | print(e)
117 |
118 | print(result)
119 | ```
120 |
121 | > `Note` 无论单发/群发短信还是指定模板ID单发/群发短信都需要从控制台中申请模板并且模板已经审核通过,才可能下发成功,否则返回失败。
122 |
123 | - **指定模板ID群发**
124 |
125 | ```python
126 | from qcloudsms_py import SmsMultiSender
127 | from qcloudsms_py.httpclient import HTTPError
128 |
129 | msender = SmsMultiSender(appid, appkey)
130 | params = ["5678"]
131 | try:
132 | result = msender.send_with_param(86, phone_numbers,
133 | template_id, params, sign=sms_sign, extend="", ext="") # 签名参数不允许为空串
134 | except HTTPError as e:
135 | print(e)
136 | except Exception as e:
137 | print(e)
138 |
139 | print(result)
140 | ```
141 |
142 | > `Note:`群发一次请求最多支持200个号码,如有对号码数量有特殊需求请联系腾讯云短信技术支持(QQ:3012203387)。
143 | > `Note` 无论单发/群发短信还是指定模板ID单发/群发短信都需要从控制台中申请模板并且模板已经审核通过,才可能下发成功,否则返回失败。
144 |
145 | - **发送语音验证码**
146 |
147 | ```python
148 | from qcloudsms_py import SmsVoiceVerifyCodeSender
149 | from qcloudsms_py.httpclient import HTTPError
150 |
151 | vvcsender = SmsVoiceVerifyCodeSender(appid, appkey)
152 | try:
153 | result = vvcsender.send("86", phone_numbers[0], "5678",
154 | playtimes=2, ext="")
155 | except HTTPError as e:
156 | print(e)
157 | except Exception as e:
158 | print(e)
159 |
160 | print(result)
161 | ```
162 |
163 | > `Note` 语音验证码发送只需提供验证码数字,例如当msg=“5678”时,您收到的语音通知为“您的语音验证码是5678”,如需自定义内容,可以使用语音通知。
164 |
165 |
166 | - **发送语音通知**
167 |
168 | ```python
169 | from qcloudsms_py import SmsVoicePromptSender
170 | from qcloudsms_py.httpclient import HTTPError
171 |
172 | vpsender = SmsVoicePromptSender(appid, appkey)
173 | try:
174 | result = vpsender.send("86", phone_numbers[0], 2, "5678",
175 | playtimes=2, ext="")
176 | except HTTPError as e:
177 | print(e)
178 | except Exception as e:
179 | print(e)
180 |
181 | print(result)
182 | ```
183 |
184 | - **拉取短信回执以及回复**
185 |
186 | ```python
187 | from qcloudsms_py import SmsStatusPuller
188 | from qcloudsms_py.httpclient import HTTPError
189 |
190 | max_num = 10 # 单次拉取最大量
191 | spuller = SmsStatusPuller(appid, appkey)
192 | try:
193 | # 拉取短信回执
194 | callback_result = spuller.pull_callback(max_num)
195 | # 拉取回复
196 | reply_result = spuller.pull_reply(max_num)
197 | except HTTPError as e:
198 | print(e)
199 | except Exception as e:
200 | print(e)
201 |
202 | print(callback_result)
203 | print(reply_result)
204 | ```
205 |
206 | > `Note:` 短信拉取功能需要联系腾讯云短信技术支持(QQ:3012203387),量大客户可以使用此功能批量拉取,其他客户不建议使用。
207 |
208 | - **拉取单个手机短信状态**
209 |
210 | ```python
211 | from qcloudsms_py import SmsMobileStatusPuller
212 | from qcloudsms_py.httpclient import HTTPError
213 |
214 | begin_time = 1511125600 # 开始时间(unix timestamp)
215 | end_time = 1511841600 # 结束时间(unix timestamp)
216 | max_num = 10 # 单次拉取最大量
217 | mspuller = SmsMobileStatusPuller(appid, appkey)
218 | try:
219 | # 拉取短信回执
220 | callback_result = mspuller.pull_callback("86", phone_numbers[0],
221 | begin_time, end_time, max_num)
222 | # 拉取回复
223 | reply_result = mspuller.pull_reply("86", phone_numbers[0],
224 | begin_time, end_time, max_num)
225 | except HTTPError as e:
226 | print(e)
227 | except Exception as e:
228 | print(e)
229 |
230 | print(callback_result)
231 | print(reply_result)
232 | ```
233 |
234 | > `Note:` 短信拉取功能需要联系腾讯云短信技术支持(QQ:3012203387),量大客户可以使用此功能批量拉取,其他客户不建议使用。
235 |
236 | - **发送海外短信**
237 |
238 | 海外短信与国内短信发送类似, 发送海外短信只需替换相应国家码。
239 |
240 |
241 | - **上传语音文件**
242 |
243 | ```python
244 | from qcloudsms_py import VoiceFileUploader
245 | from qcloudsms_py.httpclient import HTTPError
246 |
247 | # Note: 语音文件大小上传限制400K字节
248 | with open("/path/to/example.mp3", "rb") as f:
249 | content = f.read()
250 | uploader = VoiceFileUploader(appid, appkey)
251 | try:
252 | result = uploader.upload(content, content_type="mp3")
253 | except HTTPError as e:
254 | print(e)
255 | except Exception as e:
256 | print(e)
257 |
258 | # 上传成功后,result里会带有语音文件的fid
259 | print(result)
260 | ```
261 |
262 | > `Note` '语音文件上传'功能需要联系腾讯云短信技术支持(QQ:3012203387)才能开通
263 |
264 | - **按语音文件fid发送语音通知**
265 |
266 | ```python
267 | from qcloudsms_py import FileVoiceSender
268 | from qcloudsms_py.httpclient import HTTPError
269 |
270 | # Note:这里fid来自`上传语音文件`接口返回的响应,要按语音
271 | # 文件fid发送语音通知,需要先上传语音文件获取fid
272 | fid = "c799d10a43ec109f02f2288ca3c85b79e7700c98.mp3"
273 | fvsender = FileVoiceSender(appid, appkey)
274 | try:
275 | result = fvsender.send(fid, phone_numbers[0],
276 | nationcode="86", playtimes=2, ext="")
277 | except HTTPError as e:
278 | print(e)
279 | except Exception as e:
280 | print(e)
281 |
282 | print(result)
283 | ```
284 |
285 | > `Note` 按'语音文件fid发送语音通知'功能需要联系腾讯云短信技术支持(QQ:3012203387)才能开通
286 |
287 | - **指定模板发送语音通知**
288 |
289 | ```python
290 | from qcloudsms_py import TtsVoiceSender
291 | from qcloudsms_py.httpclient import HTTPError
292 |
293 | template_id = 12345
294 | params = ["5678"]
295 | tvsender = TtsVoiceSender(appid, appkey)
296 | Try:
297 | result = tvsender.send(template_id, params, phone_numbers[0],
298 | nationcode="86", playtimes=2, ext="")
299 | except HTTPError as e:
300 | print(e)
301 | except Exception as e:
302 | print(e)
303 |
304 | print(result)
305 | ```
306 |
307 | #### 使用代理
308 |
309 | 有的环境需要使用代理才能上网,可以指定HTTPSimpleClient的proxy参数来实现, 示例如下:
310 |
311 | ```python
312 | from qcloudsms_py import SmsSingleSender
313 | from qcloudsms_py.httpclient import HTTPSimpleClient, HTTPError
314 |
315 | httpclient = HTTPSimpleClient(proxy="www.proxysever.com:8080")
316 | ssender = SmsSingleSender(appid, appkey, httpclient=httpclient)
317 | template_id = 7839
318 | params = ["5678"]
319 | try:
320 | result = ssender.send_with_param(86, phone_numbers[0],
321 | template_id, params, sign=sms_sign, extend="", ext="")
322 | except HTTPError as e:
323 | print(e)
324 | except Exception as e:
325 | print(e)
326 |
327 | print(result)
328 | ```
329 |
330 | #### 统一创建对象
331 |
332 | 短信和语音各类的对象可以通过 `qcloudsms_py.QcloudSms` 统一创建,这种
333 | 方式可以避免创建对象时多次传入参数`appid` 和 `appkey`, 示例如下:
334 |
335 | ```python
336 | from qcloudsms_py import QcloudSms
337 |
338 | # 创建QcloudSms对象
339 | qcloudsms = QcloudSms(appid, appkey)
340 |
341 | # 创建单发短信(SmsSingleSender)对象
342 | ssender = qcloudsms.SmsSingleSender()
343 |
344 | # 创建上传语音文件(VoiceFileUploader)对象
345 | uploader = qcloudsms.VoiceFileUploader()
346 | ```
347 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | README
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | qcloudsms_py API documentation
7 |
8 |
9 |
10 |
11 |
551 |
552 |
853 |
854 |
925 |
926 |
1018 |
1019 |
1033 |
1034 |
1035 | Top
1036 |
1037 |
1038 |
1039 |
1040 |
1078 |
1079 |
1080 |
1081 |
1082 |
1083 |
1084 |
1085 |
1086 |
1087 | qcloudsms_py module
1088 |
1089 |
1090 | Show source ≡
1091 |
1092 |
#!/usr/bin/env python
1093 | # -*- coding: utf-8 -*-
1094 | from __future__ import absolute_import, division, print_function
1095 |
1096 | from qcloudsms_py import sms
1097 | from qcloudsms_py import voice
1098 | from qcloudsms_py import httpclient
1099 | from qcloudsms_py.sms import *
1100 | from qcloudsms_py.voice import *
1101 |
1102 |
1103 | # human-readable version number
1104 | version = "0.1.3"
1105 |
1106 | # three-tuple for programmatic comparison
1107 | version_info = (0, 1, 3)
1108 |
1109 |
1110 | class QcloudSms(object):
1111 |
1112 | SMS_CLASSES = set([cls for cls in sms.__all__])
1113 | VOICE_CLASSESS = set([cls for cls in voice.__all__])
1114 |
1115 | def __init__(self, appid, appkey, httpclient=None):
1116 | self._appid = appid
1117 | self._appkey = appkey
1118 | self._httpclient = httpclient
1119 | self._cache = {}
1120 |
1121 | def __getattr__(self, name):
1122 | if (name not in self.__class__.SMS_CLASSES and
1123 | name not in self.__class__.VOICE_CLASSESS):
1124 | raise AttributeError("{} is not in {}".format(
1125 | name, self.__class__.__name__))
1126 | if name in self._cache:
1127 | return lambda: self._cache[name]
1128 |
1129 | if name in self.__class__.SMS_CLASSES:
1130 | cls = getattr(sms, name)
1131 | else:
1132 | cls = getattr(voice, name)
1133 | self._cache[name] = obj = cls(
1134 | self._appid, self._appkey, self._httpclient
1135 | )
1136 | return lambda: obj
1137 |
1138 | def new(self, name):
1139 | if (name not in self.__class__.SMS_CLASSES and
1140 | name not in self.__class__.VOICE_CLASSESS):
1141 | raise AttributeError("{} is not in {}".format(
1142 | name, self.__class__.__name__))
1143 | if name in self.__class__.SMS_CLASSES:
1144 | return getattr(sms, name)(
1145 | self._appid, self._appkey, self._httpclient
1146 | )
1147 | else:
1148 | return getattr(voice, name)(
1149 | self._appid, self._appkey, self._httpclient
1150 | )
1151 |
1152 |
1153 |
1154 |
1155 |
1156 |
1157 |
1158 |
1159 |
1160 |
var version
1161 |
1162 |
1163 |
1164 |
1165 |
1166 |
1167 |
1168 |
var version_info
1169 |
1170 |
1171 |
1172 |
1173 |
1174 |
1175 |
1176 |
1177 |
1178 |
1179 |
1180 |
class QcloudSms
1181 |
1182 |
1183 |
1184 |
Show source ≡
1185 |
1186 |
class QcloudSms(object):
1187 |
1188 | SMS_CLASSES = set([cls for cls in sms.__all__])
1189 | VOICE_CLASSESS = set([cls for cls in voice.__all__])
1190 |
1191 | def __init__(self, appid, appkey, httpclient=None):
1192 | self._appid = appid
1193 | self._appkey = appkey
1194 | self._httpclient = httpclient
1195 | self._cache = {}
1196 |
1197 | def __getattr__(self, name):
1198 | if (name not in self.__class__.SMS_CLASSES and
1199 | name not in self.__class__.VOICE_CLASSESS):
1200 | raise AttributeError("{} is not in {}".format(
1201 | name, self.__class__.__name__))
1202 | if name in self._cache:
1203 | return lambda: self._cache[name]
1204 |
1205 | if name in self.__class__.SMS_CLASSES:
1206 | cls = getattr(sms, name)
1207 | else:
1208 | cls = getattr(voice, name)
1209 | self._cache[name] = obj = cls(
1210 | self._appid, self._appkey, self._httpclient
1211 | )
1212 | return lambda: obj
1213 |
1214 | def new(self, name):
1215 | if (name not in self.__class__.SMS_CLASSES and
1216 | name not in self.__class__.VOICE_CLASSESS):
1217 | raise AttributeError("{} is not in {}".format(
1218 | name, self.__class__.__name__))
1219 | if name in self.__class__.SMS_CLASSES:
1220 | return getattr(sms, name)(
1221 | self._appid, self._appkey, self._httpclient
1222 | )
1223 | else:
1224 | return getattr(voice, name)(
1225 | self._appid, self._appkey, self._httpclient
1226 | )
1227 |
1228 |
1229 |
1230 |
1231 |
1232 |
1233 |
1234 |
Ancestors (in MRO)
1235 |
1239 |
Class variables
1240 |
1241 |
var SMS_CLASSES
1242 |
1243 |
1244 |
1245 |
1246 |
1247 |
1248 |
1249 |
1250 |
1251 |
var VOICE_CLASSESS
1252 |
1253 |
1254 |
1255 |
1256 |
1257 |
1258 |
1259 |
1260 |
1261 |
var cls
1262 |
1263 |
1264 |
1265 |
1266 |
1267 |
1268 |
1269 |
1270 |
Methods
1271 |
1272 |
1273 |
1274 |
def __init__(
self, appid, appkey, httpclient=None)
1275 |
1276 |
1277 |
1278 |
1279 |
1280 |
1281 |
Show source ≡
1282 |
1283 |
def __init__(self, appid, appkey, httpclient=None):
1284 | self._appid = appid
1285 | self._appkey = appkey
1286 | self._httpclient = httpclient
1287 | self._cache = {}
1288 |
1289 |
1290 |
1291 |
1292 |
1293 |
1294 |
1295 |
1296 |
1297 |
1298 |
def new(
self, name)
1299 |
1300 |
1301 |
1302 |
1303 |
1304 |
1305 |
Show source ≡
1306 |
1307 |
def new(self, name):
1308 | if (name not in self.__class__.SMS_CLASSES and
1309 | name not in self.__class__.VOICE_CLASSESS):
1310 | raise AttributeError("{} is not in {}".format(
1311 | name, self.__class__.__name__))
1312 | if name in self.__class__.SMS_CLASSES:
1313 | return getattr(sms, name)(
1314 | self._appid, self._appkey, self._httpclient
1315 | )
1316 | else:
1317 | return getattr(voice, name)(
1318 | self._appid, self._appkey, self._httpclient
1319 | )
1320 |
1321 |
1322 |
1323 |
1324 |
1325 |
1326 |
1327 |
1328 |
1329 |
1330 |
1331 |
1337 |
1343 |
1349 |
1355 |
1356 |
1357 |
1358 |
1359 |
1370 |
1371 |
1372 |