# SenWeaver SMS
📲 您的一站式 Python 短信发送解决方案
> 告别繁琐的多平台适配!本库聚合了众多短信服务商,通过一致的调用方式、灵活的配置选项和内置的轮询策略,让您轻松实现高效、可靠的短信发送,并获得统一的响应结果用于监控。
[](https://badge.fury.io/py/senweaver-sms)
## 特点
1. 支持目前市面多家服务商
2. 一套写法兼容所有平台
3. 提供流畅的 Builder API,配置简单灵活
4. 内置多种服务商轮询策略、支持自定义轮询策略
5. 统一的返回值格式 (`SMSResponse`),便于日志与监控
6. 自动根据策略选择可用的服务商
7. 类型提示友好,代码健壮性高
## 平台支持
* 阿里云 (Aliyun)
* 腾讯云 (Qcloud)
* 百度智能云 (Baidu)
* 华为云 (Huawei)
* 天翼云 (Ctyun)
* UCloud
* 七牛云 (Qiniu)
* 云片 (Yunpian)
* 互亿无线 (Huyi)
* 聚合数据 (Juhe)
* 短信宝 (Smsbao)
* 持续添加中...
## 环境需求
* Python >= 3.8
## 安装
```bash
pip install senweaver-sms
```
## 使用 (推荐方式: SMSBuilder)
我们推荐使用 `SMSBuilder` 来构建和发送短信请求,它提供了链式调用和类型安全的配置方式。
```python
from senweaver_sms import SMSBuilder, PhoneNumber
from senweaver_sms.exception import GatewayErrorException, NoGatewayAvailableException
# 使用构建器配置网关
sms_request = SMSBuilder.builder() \
.aliyun( # 添加阿里云网关
access_key_id="YOUR_ALIYUN_ACCESS_KEY_ID",
access_key_secret="YOUR_ALIYUN_ACCESS_KEY_SECRET",
sign_name="你的签名"
) \
.qcloud( # 添加腾讯云网关
sdk_app_id="YOUR_TENCENT_SDK_APP_ID",
secret_id="YOUR_TENCENT_SECRET_ID",
secret_key="YOUR_TENCENT_SECRET_KEY",
sign_name="你的签名"
) \
.huawei( # 添加华为云网关
app_key="YOUR_HUAWEI_APP_KEY", # 注意:华为云的app_key是控制台的APP Key
app_secret="YOUR_HUAWEI_APP_SECRET", # 注意:华为云的app_secret是控制台的APP Secret
channel="YOUR_HUAWEI_CHANNEL", # 短信通道号
sign="你的签名" # 可选,不填则尝试用 channel
) \
.yunpian( # 添加云片网关
api_key="YOUR_YUNPIAN_API_KEY",
sign="你的签名" # 可选
) \
.timeout(10.0) # 设置全局请求超时时间 (秒)
.strategy("order") # 设置网关选择策略 ('order', 'random' 或自定义)
.debug(True) # 开启调试模式 (可选)
.build() # 构建请求对象
# 发送短信
try:
phone = "YOUR_PHONE_NUMBER"
template_id = "YOUR_TEMPLATE_ID" # 不同平台模板ID可能不同
data = {"code": "123456", "minutes": 5}
print(f"向 {phone} 发送短信...")
# send 方法参数:接收者手机号, content(可选,文本内容), template(可选,模板ID), data(可选,模板参数), gateways(可选,指定网关列表), strategy(可选,指定策略)
response = sms_request.send(
to=phone,
template=template_id,
data=data
)
print("\n发送成功!")
print(f"网关: {response.gateway}")
print(f"状态: {response.status.name}") # SUCCESS 或 FAILED
print(f"消息ID: {response.message_id}") # 网关返回的消息标识
print(f"原始响应: {response.raw_response}")
except (GatewayErrorException, NoGatewayAvailableException) as e:
print(f"\n发送失败: {e}")
if isinstance(e, GatewayErrorException):
print(f" 错误网关: {e.gateway}")
print(f" 错误代码: {e.code}")
print(f" 错误详情: {e.data}")
elif isinstance(e, NoGatewayAvailableException):
print(" 没有可用的网关成功发送短信。尝试详情:")
if hasattr(e, 'details') and e.details and 'responses' in e.details:
for failed_resp in e.details['responses']:
print(f" - 网关 {failed_resp.gateway} 失败: {failed_resp.error}")
except ValueError as e:
print(f"\n配置或参数错误: {e}")
except Exception as e:
print(f"\n发生未知错误: {e}")
# 发送国际短信 (使用PhoneNumber对象)
try:
number = PhoneNumber('YOUR_PHONE_NUMBER', '31') # 31是荷兰的国家码
print(f"\n向 {number.get_universal_format()} 发送国际短信...")
response = sms_request.send(
to=number,
template=template_id,
data=data
)
print("发送成功!")
print(f"消息ID: {response.message_id}")
except Exception as e:
print(f"发送失败: {e}")
# 批量发送 (同一内容给多人)
try:
phones = ["YOUR_PHONE_NUMBER1", "YOUR_PHONE_NUMBER2"]
print(f"\n向 {len(phones)} 个号码批量发送短信...")
batch_response = sms_request.batch_send(
to_list=phones,
template=template_id,
data=data
)
print(f"批量发送完成: {batch_response.success_count} 成功, {batch_response.failure_count} 失败")
for resp in batch_response.get_failed_responses():
print(f" - {resp.phone_number} 发送失败: {resp.error}")
except Exception as e:
print(f"批量发送失败: {e}")
```
## 网关配置 (`GatewayConfig`)
使用 `SMSBuilder` 添加网关时,可以通过特定网关的辅助方法(如 `.aliyun()`, `.qcloud()`)或通用的 `.gateway()` 方法进行配置。`GatewayConfig` 对象包含了所有可能的配置项:
* 通用认证: `app_id`, `app_key`, `app_secret`
* 通用选项: `sign`, `region`, `version`
* 通用高级: `timeout`, `ssl_verify`
* 特定网关: `invoke_id` (百度), `signature_id` (百度), `channel` (华为), `endpoint` (华为), `callback_url` (华为), `project_id` (UCloud)
详细的参数映射关系请参考 `senweaver_sms/config.py` 中的 `GatewayConfig` 类文档字符串。
## 短信内容 (`Message`)
发送短信时,可以通过 `content` 参数发送纯文本内容(适用于云片、短信宝等),或通过 `template` 和 `data` 参数使用模板发送(适用于阿里云、腾讯云等)。
```python
# 文本内容发送
sms_request.send(phone, content="【签名】您的验证码是1234")
# 模板发送
sms_request.send(phone, template="TEMPLATE_ID", data={"code": 1234})
```
`data` 参数可以是字典或列表(部分网关如腾讯云、UCloud会按顺序使用列表中的值)。
## 统一响应 (`SMSResponse` / `SMSBatchResponse`)
* **单条发送**: `send` 方法返回一个 `SMSResponse` 对象,包含:
* `gateway` (str): 实际发送成功的网关名称。
* `status` (SMSStatus): `SMSStatus.SUCCESS` 或 `SMSStatus.FAILED`。
* `message_id` (Optional[str]): 网关返回的消息唯一标识 (如果可用)。
* `raw_response` (Dict[str, Any]): 网关返回的原始响应数据。
* `error` (Optional[SMSError]): 如果失败,包含错误代码和消息。
* `fee` (int): 预估的计费条数。
* `send_time` (datetime): 发送时间。
* **批量发送**: `batch_send` 方法返回一个 `SMSBatchResponse` 对象,包含一个 `SMSResponse` 列表以及成功和失败的统计。
## 异常处理
* `GatewayErrorException`: 特定网关发送失败时抛出,包含错误代码、消息和原始数据。
* `NoGatewayAvailableException`: 所有尝试的网关都发送失败时抛出。
* `NoGatewaySelectedException`: 没有配置任何可用网关时抛出。
* `InvalidArgumentException`: 配置或参数无效时抛出。
* `ValueError`: 配置验证失败时抛出。
## 自定义网关与策略
(这部分可以保持不变或根据需要简化)
...
## 贡献
欢迎提交 Pull Request 或 Issue!
## License
MIT License
Raw data
{
"_id": null,
"home_page": "https://github.com/senweaver/senweaver-sms",
"name": "senweaver-sms",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "sms, message, yunpian, aliyun, qcloud, tencent, senweaver",
"author": "senweaver",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/10/fd/53b339f0bf3d96309494f13eb84d2eb494de31a75563178d2a1305ec7089/senweaver_sms-0.1.2.tar.gz",
"platform": null,
"description": "# SenWeaver SMS\n\n\ud83d\udcf2 \u60a8\u7684\u4e00\u7ad9\u5f0f Python \u77ed\u4fe1\u53d1\u9001\u89e3\u51b3\u65b9\u6848\n\n> \u544a\u522b\u7e41\u7410\u7684\u591a\u5e73\u53f0\u9002\u914d\uff01\u672c\u5e93\u805a\u5408\u4e86\u4f17\u591a\u77ed\u4fe1\u670d\u52a1\u5546\uff0c\u901a\u8fc7\u4e00\u81f4\u7684\u8c03\u7528\u65b9\u5f0f\u3001\u7075\u6d3b\u7684\u914d\u7f6e\u9009\u9879\u548c\u5185\u7f6e\u7684\u8f6e\u8be2\u7b56\u7565\uff0c\u8ba9\u60a8\u8f7b\u677e\u5b9e\u73b0\u9ad8\u6548\u3001\u53ef\u9760\u7684\u77ed\u4fe1\u53d1\u9001\uff0c\u5e76\u83b7\u5f97\u7edf\u4e00\u7684\u54cd\u5e94\u7ed3\u679c\u7528\u4e8e\u76d1\u63a7\u3002\n\n[](https://badge.fury.io/py/senweaver-sms)\n\n## \u7279\u70b9\n\n1. \u652f\u6301\u76ee\u524d\u5e02\u9762\u591a\u5bb6\u670d\u52a1\u5546\n2. \u4e00\u5957\u5199\u6cd5\u517c\u5bb9\u6240\u6709\u5e73\u53f0\n3. \u63d0\u4f9b\u6d41\u7545\u7684 Builder API\uff0c\u914d\u7f6e\u7b80\u5355\u7075\u6d3b\n4. \u5185\u7f6e\u591a\u79cd\u670d\u52a1\u5546\u8f6e\u8be2\u7b56\u7565\u3001\u652f\u6301\u81ea\u5b9a\u4e49\u8f6e\u8be2\u7b56\u7565\n5. \u7edf\u4e00\u7684\u8fd4\u56de\u503c\u683c\u5f0f (`SMSResponse`)\uff0c\u4fbf\u4e8e\u65e5\u5fd7\u4e0e\u76d1\u63a7\n6. \u81ea\u52a8\u6839\u636e\u7b56\u7565\u9009\u62e9\u53ef\u7528\u7684\u670d\u52a1\u5546\n7. \u7c7b\u578b\u63d0\u793a\u53cb\u597d\uff0c\u4ee3\u7801\u5065\u58ee\u6027\u9ad8\n\n## \u5e73\u53f0\u652f\u6301\n\n* \u963f\u91cc\u4e91 (Aliyun)\n* \u817e\u8baf\u4e91 (Qcloud)\n* \u767e\u5ea6\u667a\u80fd\u4e91 (Baidu)\n* \u534e\u4e3a\u4e91 (Huawei)\n* \u5929\u7ffc\u4e91 (Ctyun)\n* UCloud\n* \u4e03\u725b\u4e91 (Qiniu)\n* \u4e91\u7247 (Yunpian)\n* \u4e92\u4ebf\u65e0\u7ebf (Huyi)\n* \u805a\u5408\u6570\u636e (Juhe)\n* \u77ed\u4fe1\u5b9d (Smsbao)\n* \u6301\u7eed\u6dfb\u52a0\u4e2d...\n\n## \u73af\u5883\u9700\u6c42\n\n* Python >= 3.8\n\n## \u5b89\u88c5\n\n```bash\npip install senweaver-sms\n```\n\n## \u4f7f\u7528 (\u63a8\u8350\u65b9\u5f0f: SMSBuilder)\n\n\u6211\u4eec\u63a8\u8350\u4f7f\u7528 `SMSBuilder` \u6765\u6784\u5efa\u548c\u53d1\u9001\u77ed\u4fe1\u8bf7\u6c42\uff0c\u5b83\u63d0\u4f9b\u4e86\u94fe\u5f0f\u8c03\u7528\u548c\u7c7b\u578b\u5b89\u5168\u7684\u914d\u7f6e\u65b9\u5f0f\u3002\n\n```python\nfrom senweaver_sms import SMSBuilder, PhoneNumber\nfrom senweaver_sms.exception import GatewayErrorException, NoGatewayAvailableException\n\n# \u4f7f\u7528\u6784\u5efa\u5668\u914d\u7f6e\u7f51\u5173\nsms_request = SMSBuilder.builder() \\\n .aliyun( # \u6dfb\u52a0\u963f\u91cc\u4e91\u7f51\u5173\n access_key_id=\"YOUR_ALIYUN_ACCESS_KEY_ID\",\n access_key_secret=\"YOUR_ALIYUN_ACCESS_KEY_SECRET\",\n sign_name=\"\u4f60\u7684\u7b7e\u540d\"\n ) \\\n .qcloud( # \u6dfb\u52a0\u817e\u8baf\u4e91\u7f51\u5173\n sdk_app_id=\"YOUR_TENCENT_SDK_APP_ID\",\n secret_id=\"YOUR_TENCENT_SECRET_ID\",\n secret_key=\"YOUR_TENCENT_SECRET_KEY\",\n sign_name=\"\u4f60\u7684\u7b7e\u540d\"\n ) \\\n .huawei( # \u6dfb\u52a0\u534e\u4e3a\u4e91\u7f51\u5173\n app_key=\"YOUR_HUAWEI_APP_KEY\", # \u6ce8\u610f\uff1a\u534e\u4e3a\u4e91\u7684app_key\u662f\u63a7\u5236\u53f0\u7684APP Key\n app_secret=\"YOUR_HUAWEI_APP_SECRET\", # \u6ce8\u610f\uff1a\u534e\u4e3a\u4e91\u7684app_secret\u662f\u63a7\u5236\u53f0\u7684APP Secret\n channel=\"YOUR_HUAWEI_CHANNEL\", # \u77ed\u4fe1\u901a\u9053\u53f7\n sign=\"\u4f60\u7684\u7b7e\u540d\" # \u53ef\u9009\uff0c\u4e0d\u586b\u5219\u5c1d\u8bd5\u7528 channel\n ) \\\n .yunpian( # \u6dfb\u52a0\u4e91\u7247\u7f51\u5173\n api_key=\"YOUR_YUNPIAN_API_KEY\",\n sign=\"\u4f60\u7684\u7b7e\u540d\" # \u53ef\u9009\n ) \\\n .timeout(10.0) # \u8bbe\u7f6e\u5168\u5c40\u8bf7\u6c42\u8d85\u65f6\u65f6\u95f4 (\u79d2)\n .strategy(\"order\") # \u8bbe\u7f6e\u7f51\u5173\u9009\u62e9\u7b56\u7565 ('order', 'random' \u6216\u81ea\u5b9a\u4e49)\n .debug(True) # \u5f00\u542f\u8c03\u8bd5\u6a21\u5f0f (\u53ef\u9009)\n .build() # \u6784\u5efa\u8bf7\u6c42\u5bf9\u8c61\n\n# \u53d1\u9001\u77ed\u4fe1\ntry:\n phone = \"YOUR_PHONE_NUMBER\"\n template_id = \"YOUR_TEMPLATE_ID\" # \u4e0d\u540c\u5e73\u53f0\u6a21\u677fID\u53ef\u80fd\u4e0d\u540c\n data = {\"code\": \"123456\", \"minutes\": 5}\n \n print(f\"\u5411 {phone} \u53d1\u9001\u77ed\u4fe1...\")\n # send \u65b9\u6cd5\u53c2\u6570\uff1a\u63a5\u6536\u8005\u624b\u673a\u53f7, content(\u53ef\u9009,\u6587\u672c\u5185\u5bb9), template(\u53ef\u9009,\u6a21\u677fID), data(\u53ef\u9009,\u6a21\u677f\u53c2\u6570), gateways(\u53ef\u9009,\u6307\u5b9a\u7f51\u5173\u5217\u8868), strategy(\u53ef\u9009,\u6307\u5b9a\u7b56\u7565)\n response = sms_request.send(\n to=phone, \n template=template_id, \n data=data\n )\n \n print(\"\\n\u53d1\u9001\u6210\u529f!\")\n print(f\"\u7f51\u5173: {response.gateway}\")\n print(f\"\u72b6\u6001: {response.status.name}\") # SUCCESS \u6216 FAILED\n print(f\"\u6d88\u606fID: {response.message_id}\") # \u7f51\u5173\u8fd4\u56de\u7684\u6d88\u606f\u6807\u8bc6\n print(f\"\u539f\u59cb\u54cd\u5e94: {response.raw_response}\")\n\nexcept (GatewayErrorException, NoGatewayAvailableException) as e:\n print(f\"\\n\u53d1\u9001\u5931\u8d25: {e}\")\n if isinstance(e, GatewayErrorException):\n print(f\" \u9519\u8bef\u7f51\u5173: {e.gateway}\")\n print(f\" \u9519\u8bef\u4ee3\u7801: {e.code}\")\n print(f\" \u9519\u8bef\u8be6\u60c5: {e.data}\")\n elif isinstance(e, NoGatewayAvailableException):\n print(\" \u6ca1\u6709\u53ef\u7528\u7684\u7f51\u5173\u6210\u529f\u53d1\u9001\u77ed\u4fe1\u3002\u5c1d\u8bd5\u8be6\u60c5:\")\n if hasattr(e, 'details') and e.details and 'responses' in e.details:\n for failed_resp in e.details['responses']:\n print(f\" - \u7f51\u5173 {failed_resp.gateway} \u5931\u8d25: {failed_resp.error}\")\n\nexcept ValueError as e:\n print(f\"\\n\u914d\u7f6e\u6216\u53c2\u6570\u9519\u8bef: {e}\")\n \nexcept Exception as e:\n print(f\"\\n\u53d1\u751f\u672a\u77e5\u9519\u8bef: {e}\")\n\n# \u53d1\u9001\u56fd\u9645\u77ed\u4fe1 (\u4f7f\u7528PhoneNumber\u5bf9\u8c61)\ntry:\n number = PhoneNumber('YOUR_PHONE_NUMBER', '31') # 31\u662f\u8377\u5170\u7684\u56fd\u5bb6\u7801\n print(f\"\\n\u5411 {number.get_universal_format()} \u53d1\u9001\u56fd\u9645\u77ed\u4fe1...\")\n response = sms_request.send(\n to=number,\n template=template_id,\n data=data\n )\n print(\"\u53d1\u9001\u6210\u529f!\")\n print(f\"\u6d88\u606fID: {response.message_id}\")\nexcept Exception as e:\n print(f\"\u53d1\u9001\u5931\u8d25: {e}\")\n \n# \u6279\u91cf\u53d1\u9001 (\u540c\u4e00\u5185\u5bb9\u7ed9\u591a\u4eba)\ntry:\n phones = [\"YOUR_PHONE_NUMBER1\", \"YOUR_PHONE_NUMBER2\"]\n print(f\"\\n\u5411 {len(phones)} \u4e2a\u53f7\u7801\u6279\u91cf\u53d1\u9001\u77ed\u4fe1...\")\n batch_response = sms_request.batch_send(\n to_list=phones,\n template=template_id,\n data=data\n )\n print(f\"\u6279\u91cf\u53d1\u9001\u5b8c\u6210: {batch_response.success_count} \u6210\u529f, {batch_response.failure_count} \u5931\u8d25\")\n for resp in batch_response.get_failed_responses():\n print(f\" - {resp.phone_number} \u53d1\u9001\u5931\u8d25: {resp.error}\")\nexcept Exception as e:\n print(f\"\u6279\u91cf\u53d1\u9001\u5931\u8d25: {e}\")\n```\n\n## \u7f51\u5173\u914d\u7f6e (`GatewayConfig`)\n\n\u4f7f\u7528 `SMSBuilder` \u6dfb\u52a0\u7f51\u5173\u65f6\uff0c\u53ef\u4ee5\u901a\u8fc7\u7279\u5b9a\u7f51\u5173\u7684\u8f85\u52a9\u65b9\u6cd5\uff08\u5982 `.aliyun()`, `.qcloud()`\uff09\u6216\u901a\u7528\u7684 `.gateway()` \u65b9\u6cd5\u8fdb\u884c\u914d\u7f6e\u3002`GatewayConfig` \u5bf9\u8c61\u5305\u542b\u4e86\u6240\u6709\u53ef\u80fd\u7684\u914d\u7f6e\u9879\uff1a\n\n* \u901a\u7528\u8ba4\u8bc1: `app_id`, `app_key`, `app_secret`\n* \u901a\u7528\u9009\u9879: `sign`, `region`, `version`\n* \u901a\u7528\u9ad8\u7ea7: `timeout`, `ssl_verify`\n* \u7279\u5b9a\u7f51\u5173: `invoke_id` (\u767e\u5ea6), `signature_id` (\u767e\u5ea6), `channel` (\u534e\u4e3a), `endpoint` (\u534e\u4e3a), `callback_url` (\u534e\u4e3a), `project_id` (UCloud)\n\n\u8be6\u7ec6\u7684\u53c2\u6570\u6620\u5c04\u5173\u7cfb\u8bf7\u53c2\u8003 `senweaver_sms/config.py` \u4e2d\u7684 `GatewayConfig` \u7c7b\u6587\u6863\u5b57\u7b26\u4e32\u3002\n\n## \u77ed\u4fe1\u5185\u5bb9 (`Message`)\n\n\u53d1\u9001\u77ed\u4fe1\u65f6\uff0c\u53ef\u4ee5\u901a\u8fc7 `content` \u53c2\u6570\u53d1\u9001\u7eaf\u6587\u672c\u5185\u5bb9\uff08\u9002\u7528\u4e8e\u4e91\u7247\u3001\u77ed\u4fe1\u5b9d\u7b49\uff09\uff0c\u6216\u901a\u8fc7 `template` \u548c `data` \u53c2\u6570\u4f7f\u7528\u6a21\u677f\u53d1\u9001\uff08\u9002\u7528\u4e8e\u963f\u91cc\u4e91\u3001\u817e\u8baf\u4e91\u7b49\uff09\u3002\n\n```python\n# \u6587\u672c\u5185\u5bb9\u53d1\u9001\nsms_request.send(phone, content=\"\u3010\u7b7e\u540d\u3011\u60a8\u7684\u9a8c\u8bc1\u7801\u662f1234\")\n\n# \u6a21\u677f\u53d1\u9001\nsms_request.send(phone, template=\"TEMPLATE_ID\", data={\"code\": 1234})\n```\n\n`data` \u53c2\u6570\u53ef\u4ee5\u662f\u5b57\u5178\u6216\u5217\u8868\uff08\u90e8\u5206\u7f51\u5173\u5982\u817e\u8baf\u4e91\u3001UCloud\u4f1a\u6309\u987a\u5e8f\u4f7f\u7528\u5217\u8868\u4e2d\u7684\u503c\uff09\u3002\n\n## \u7edf\u4e00\u54cd\u5e94 (`SMSResponse` / `SMSBatchResponse`)\n\n* **\u5355\u6761\u53d1\u9001**: `send` \u65b9\u6cd5\u8fd4\u56de\u4e00\u4e2a `SMSResponse` \u5bf9\u8c61\uff0c\u5305\u542b\uff1a\n * `gateway` (str): \u5b9e\u9645\u53d1\u9001\u6210\u529f\u7684\u7f51\u5173\u540d\u79f0\u3002\n * `status` (SMSStatus): `SMSStatus.SUCCESS` \u6216 `SMSStatus.FAILED`\u3002\n * `message_id` (Optional[str]): \u7f51\u5173\u8fd4\u56de\u7684\u6d88\u606f\u552f\u4e00\u6807\u8bc6 (\u5982\u679c\u53ef\u7528)\u3002\n * `raw_response` (Dict[str, Any]): \u7f51\u5173\u8fd4\u56de\u7684\u539f\u59cb\u54cd\u5e94\u6570\u636e\u3002\n * `error` (Optional[SMSError]): \u5982\u679c\u5931\u8d25\uff0c\u5305\u542b\u9519\u8bef\u4ee3\u7801\u548c\u6d88\u606f\u3002\n * `fee` (int): \u9884\u4f30\u7684\u8ba1\u8d39\u6761\u6570\u3002\n * `send_time` (datetime): \u53d1\u9001\u65f6\u95f4\u3002\n* **\u6279\u91cf\u53d1\u9001**: `batch_send` \u65b9\u6cd5\u8fd4\u56de\u4e00\u4e2a `SMSBatchResponse` \u5bf9\u8c61\uff0c\u5305\u542b\u4e00\u4e2a `SMSResponse` \u5217\u8868\u4ee5\u53ca\u6210\u529f\u548c\u5931\u8d25\u7684\u7edf\u8ba1\u3002\n\n## \u5f02\u5e38\u5904\u7406\n\n* `GatewayErrorException`: \u7279\u5b9a\u7f51\u5173\u53d1\u9001\u5931\u8d25\u65f6\u629b\u51fa\uff0c\u5305\u542b\u9519\u8bef\u4ee3\u7801\u3001\u6d88\u606f\u548c\u539f\u59cb\u6570\u636e\u3002\n* `NoGatewayAvailableException`: \u6240\u6709\u5c1d\u8bd5\u7684\u7f51\u5173\u90fd\u53d1\u9001\u5931\u8d25\u65f6\u629b\u51fa\u3002\n* `NoGatewaySelectedException`: \u6ca1\u6709\u914d\u7f6e\u4efb\u4f55\u53ef\u7528\u7f51\u5173\u65f6\u629b\u51fa\u3002\n* `InvalidArgumentException`: \u914d\u7f6e\u6216\u53c2\u6570\u65e0\u6548\u65f6\u629b\u51fa\u3002\n* `ValueError`: \u914d\u7f6e\u9a8c\u8bc1\u5931\u8d25\u65f6\u629b\u51fa\u3002\n\n## \u81ea\u5b9a\u4e49\u7f51\u5173\u4e0e\u7b56\u7565\n\n(\u8fd9\u90e8\u5206\u53ef\u4ee5\u4fdd\u6301\u4e0d\u53d8\u6216\u6839\u636e\u9700\u8981\u7b80\u5316)\n\n...\n\n## \u8d21\u732e\n\n\u6b22\u8fce\u63d0\u4ea4 Pull Request \u6216 Issue\uff01\n\n## License\n\nMIT License\n",
"bugtrack_url": null,
"license": null,
"summary": "\u60a8\u7684\u4e00\u7ad9\u5f0f Python \u77ed\u4fe1\u53d1\u9001\u89e3\u51b3\u65b9\u6848",
"version": "0.1.2",
"project_urls": {
"Bug Reports": "https://github.com/senweaver/senweaver-sms/issues",
"Homepage": "https://github.com/senweaver/senweaver-sms",
"Source": "https://github.com/senweaver/senweaver-sms"
},
"split_keywords": [
"sms",
" message",
" yunpian",
" aliyun",
" qcloud",
" tencent",
" senweaver"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "b23f1e807481229c04e79b25991cb8954db2ce9409617680ddf4d0b9d8bd7163",
"md5": "cd433ef496029f69bf6d07c982b1688b",
"sha256": "ba57b5b279b37765c8f0ede4dc61105e3790a2fe0080dac5c98cf19c1af9cec2"
},
"downloads": -1,
"filename": "senweaver_sms-0.1.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "cd433ef496029f69bf6d07c982b1688b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 50062,
"upload_time": "2025-08-26T07:38:21",
"upload_time_iso_8601": "2025-08-26T07:38:21.178311Z",
"url": "https://files.pythonhosted.org/packages/b2/3f/1e807481229c04e79b25991cb8954db2ce9409617680ddf4d0b9d8bd7163/senweaver_sms-0.1.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "10fd53b339f0bf3d96309494f13eb84d2eb494de31a75563178d2a1305ec7089",
"md5": "d5d04a87fe963151609c9c9c8920867f",
"sha256": "dfe1c39fb6e738bef36d2fa0051137fc710f95142f846e5c8145bd2ed4b97cd6"
},
"downloads": -1,
"filename": "senweaver_sms-0.1.2.tar.gz",
"has_sig": false,
"md5_digest": "d5d04a87fe963151609c9c9c8920867f",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 32969,
"upload_time": "2025-08-26T07:38:22",
"upload_time_iso_8601": "2025-08-26T07:38:22.273889Z",
"url": "https://files.pythonhosted.org/packages/10/fd/53b339f0bf3d96309494f13eb84d2eb494de31a75563178d2a1305ec7089/senweaver_sms-0.1.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-26 07:38:22",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "senweaver",
"github_project": "senweaver-sms",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "senweaver-sms"
}