-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
190 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# tc_sms | ||
|
||
> 简单易用的 腾讯云SMS短信发送 SDK | ||
### 基础示例 | ||
|
||
```ini | ||
# .env | ||
TENCENTCLOUD_SECRET_ID=AKIDxxxxxx | ||
TENCENTCLOUD_SECRET_KEY=APxxxxxx | ||
TC_SDK_APP_ID=1xxxxxx | ||
``` | ||
|
||
```go | ||
// sms_job.go | ||
import ( | ||
// 自动加载.env环境变量 | ||
_ "github.com/joho/godotenv/autoload" | ||
// 引入tc_sms | ||
"gitee.com/we-mid/go/tc_sms" | ||
) | ||
|
||
var ( | ||
// 腾讯云-短信-国内短信-正文模板管理 | ||
// https://console.cloud.tencent.com/smsv2/csms-template | ||
templateId = "2197493" // 运营数据通知 | ||
template = `{1} 近期运营数据: | ||
*{2} PV:[{3}] UV:[{4}] 留存:[{5}] | ||
*{6} PV:[{7}] UV:[{8}] 留存:[{9}] | ||
*{10} PV:[{11}] UV:[{12}] 留存:[{13}] | ||
*{14} PV:[{15}] UV:[{16}] 留存:[{17}]` | ||
feeLimit = 3 // 单条消息发送fee上限设定 | ||
sigName = "XX应用" // 短信签名 | ||
phones = []string{"+8613xxxx", "+8618xxxx", "+8613xxxx"} // 接收手机号码 | ||
) | ||
|
||
func smsJob() { | ||
// 组装参数 | ||
var params []string | ||
// ... | ||
// 发送前预览完整文本,自动计算fee | ||
result, n, fee := tc_sms.SmsPreview(template, params) | ||
log.Println("smsJob preview:", result) | ||
log.Printf("smsJob preview: n=%d, fee=%d\n", n, fee) | ||
// 针对fee设置风控门槛 | ||
if fee > feeLimit { | ||
log.Printf("smsJob fee exceeded! n=%d, fee=%d\n", n, fee) | ||
return | ||
} | ||
// 发送短信 | ||
res, err := tc_sms.SmsSend(signName, templateId, params, phones) | ||
if err != nil { | ||
log.Println("smsJob error:", err) | ||
return | ||
} | ||
// 检查返回结果是否全部发送成功 | ||
str := res.ToJsonString() | ||
if strings.Count(str, "send success") < len(phones) { | ||
log.Println("smsJob some failed", str) | ||
return | ||
} | ||
log.Println("smsJob all success:", str) | ||
} | ||
``` | ||
|
||
### 错误码 InvalidParameterValue.TemplateParameterLengthLimit 及文本截断 | ||
|
||
```go | ||
// 注意:错误码 InvalidParameterValue.TemplateParameterLengthLimit | ||
// 非验证码短信:每个变量取值最多支持6个字符。 | ||
// https://cloud.tencent.cn/document/product/382/52075 | ||
const paramLimit = 6 | ||
|
||
func smsJob() { | ||
// ... | ||
for i, v := range params { | ||
// ❌ 注意:错误的截断方式 | ||
// if len(v) > paramLimit { | ||
// params[i] = v[:paramLimit] | ||
// } | ||
// ✅ 注意:正确处理中文字符长度 | ||
if len([]rune(v)) > paramLimit { | ||
params[i] = truncateString(v, paramLimit) // 直接截断 | ||
// ...或进行其他自定义的智能截断处理 | ||
} | ||
} | ||
// ... | ||
} | ||
|
||
func truncateString(s string, length int) string { | ||
runes := []rune(s) | ||
if len(runes) <= length { | ||
return s | ||
} | ||
return string(runes[:length]) | ||
} | ||
``` | ||
|
||
### 参考链接 | ||
|
||
- 腾讯云-短信-国内短信-正文模板管理:https://console.cloud.tencent.com/smsv2/csms-template | ||
- 关于单条短信计费fee:https://console.cloud.tencent.com/smsv2/csms-template/create | ||
- 非验证码短信:每个变量取值最多支持6个字符:https://cloud.tencent.cn/document/product/382/52075 | ||
- 参考了GitHub上的代码:https://github.com/ixre/go2o/blob/2c7f7c875501432b008b84636ab41cdac5527bd1/core/sp/tencent/tecent_sms.go |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module gitee.com/we-mid/go/tc_sms | ||
|
||
go 1.21.1 | ||
|
||
require ( | ||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.975 | ||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.975 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.975 h1:MvrNR+UtZhinneKgDngVlsm2kzuqOQ25rfwhaxedptE= | ||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.975/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0= | ||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.975 h1:nFBhBNjeQO7TgMdMgYg1d7JhOamooper7WJ7OQYjHKI= | ||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.975/go.mod h1:XXAOh54ULn6wv0KPpFX9DI26lBujGeldB/sQgMMHn98= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package tc_sms | ||
|
||
import ( | ||
"math" | ||
"regexp" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// 注意:关于单条短信计费fee -- 1. 汉字、字母、数字、标点符号(不区分全角/半角)以及空格等,都按1个字计算 | ||
// 2. 国内短信短信长度(签名+正文)不超过70字时,按照1条短信计费;超过70字即为长短信时,按67字/条分隔成多条计费,但会在1条短信内呈现。例如,短信长度为150字,则按照67字/67字/16字分隔成3条计费 | ||
// https://console.cloud.tencent.com/smsv2/csms-template/create | ||
const nPerFee = 67 | ||
|
||
// 发送前预览完整文本,自动计算fee | ||
func SmsPreview(template string, params []string) (string, int, int) { | ||
out := replacePlaceholders(template, params) | ||
n := len([]rune(out)) // 注意是 字符数 | ||
return out, n, int(math.Ceil(float64(n) / float64(nPerFee))) | ||
} | ||
|
||
func replacePlaceholders(s string, params []string) string { | ||
// 正则表达式匹配形如 {数字} 的模式 | ||
reTmpl := regexp.MustCompile(`\{(\d+)\}`) | ||
return reTmpl.ReplaceAllStringFunc(s, func(match string) string { | ||
// 提取数字部分并转换为整型 | ||
indexStr := strings.Trim(match, "{}") | ||
index, err := strconv.Atoi(indexStr) | ||
index -= 1 | ||
if err != nil { | ||
return match // 如果转换失败,返回原样 | ||
} | ||
// 确保索引在切片范围内 | ||
if index < 0 || index >= len(params) { | ||
return match // 如果索引越界,返回原样 | ||
} | ||
return params[index] | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package tc_sms | ||
|
||
import ( | ||
"os" | ||
|
||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" | ||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" | ||
"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/regions" | ||
sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111" | ||
) | ||
|
||
// 参考了GitHub上的代码 | ||
// https://github.com/ixre/go2o/blob/2c7f7c875501432b008b84636ab41cdac5527bd1/core/sp/tencent/tecent_sms.go | ||
func SmsSend(signName, templateId string, params, phones []string) (*sms.SendSmsResponse, error) { | ||
// 硬编码密钥到代码中有可能随代码泄露而暴露,有安全隐患,并不推荐。 | ||
// 为了保护密钥安全,建议将密钥设置在环境变量中或者配置文件中,请参考本文凭证管理章节。 | ||
credential := common.NewCredential( | ||
os.Getenv("TENCENTCLOUD_SECRET_ID"), | ||
os.Getenv("TENCENTCLOUD_SECRET_KEY"), | ||
) | ||
cpf := profile.NewClientProfile() | ||
cpf.HttpProfile.ReqMethod = "POST" | ||
cpf.HttpProfile.Endpoint = "sms.tencentcloudapi.com" | ||
cpf.SignMethod = "HmacSHA1" | ||
client, _ := sms.NewClient(credential, regions.Guangzhou, cpf) | ||
|
||
req := sms.NewSendSmsRequest() | ||
// 配置签名和应用Id | ||
req.SmsSdkAppId = common.StringPtr(os.Getenv("TC_SDK_APP_ID")) | ||
req.SignName = common.StringPtr(signName) | ||
req.TemplateId = common.StringPtr(templateId) | ||
req.TemplateParamSet = common.StringPtrs(params) | ||
req.PhoneNumberSet = common.StringPtrs(phones) | ||
return client.SendSms(req) | ||
} |