153 lines
3.4 KiB
Go
153 lines
3.4 KiB
Go
package mail
|
||
|
||
import (
|
||
"bytes"
|
||
"context"
|
||
"crypto/tls"
|
||
"fmt"
|
||
"html/template"
|
||
"net/mail"
|
||
"net/smtp"
|
||
"strings"
|
||
|
||
"bsm/full/module/base/sender/internal/config"
|
||
"bsm/full/module/base/sender/internal/excode"
|
||
"bsm/full/module/base/sender/internal/impl"
|
||
"bsm/full/module/base/sender/internal/models"
|
||
pb "bsm/full/module/base/sender/pb"
|
||
"git.apinb.com/bsm-sdk/core/errcode"
|
||
"git.apinb.com/bsm-sdk/core/vars"
|
||
)
|
||
|
||
func Send(ctx context.Context, in *pb.SendMailRequest) (reply *pb.SendMailReply, err error) {
|
||
provider := strings.ToLower(in.GetProvider())
|
||
|
||
// 校验参数
|
||
if in.GetTemplateKey() == "" || provider == "" || in.GetTo() == "" {
|
||
return nil, errcode.ErrInvalidArgument
|
||
}
|
||
|
||
// 校验配置
|
||
cfg, ok := config.Spec.SMTP[provider]
|
||
if !ok || cfg == nil {
|
||
return nil, excode.ErrProviderIsNil
|
||
}
|
||
|
||
// 检验邮箱格式
|
||
if !ValidateEmail(in.GetTo()) {
|
||
return nil, excode.ErrEmail
|
||
}
|
||
|
||
// 获取模板
|
||
var tplRecord models.SenderTemplate
|
||
err = impl.DBService.Where("key=?", in.GetTemplateKey()).First(&tplRecord).Error
|
||
if err != nil {
|
||
return nil, errcode.ErrNotFound(1404, "template")
|
||
}
|
||
|
||
// 解析模板
|
||
tmpl, err := template.New("page").Parse(tplRecord.Body)
|
||
if err != nil {
|
||
return nil, excode.ErrTemplate
|
||
}
|
||
|
||
// 发送邮件
|
||
switch provider {
|
||
case "qq":
|
||
err = QQ(cfg, tmpl, in.GetTo(), tplRecord.Subjet, in.GetParamters())
|
||
default:
|
||
return nil, excode.ErrNotProvider
|
||
}
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &pb.SendMailReply{
|
||
Data: vars.OK,
|
||
}, nil
|
||
}
|
||
|
||
func ValidateEmail(s string) bool {
|
||
_, err := mail.ParseAddress(s)
|
||
return err == nil
|
||
}
|
||
|
||
func QQ(cfg *config.SmtpConf, tmpl *template.Template, to string, subject string, args map[string]string) error {
|
||
// 建立TLS加密连接
|
||
conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", cfg.Endpoint, cfg.Port), &tls.Config{
|
||
ServerName: cfg.Endpoint,
|
||
MinVersion: tls.VersionTLS12, // 强制TLS1.2+
|
||
InsecureSkipVerify: false,
|
||
})
|
||
if err != nil {
|
||
fmt.Println("TLS连接失败: ", err)
|
||
return err
|
||
}
|
||
|
||
// 创建SMTP客户端(带超时控制)
|
||
client, err := smtp.NewClient(conn, cfg.Endpoint)
|
||
if err != nil {
|
||
client.Close()
|
||
fmt.Println("SMTP客户端初始化失败: ", err)
|
||
return err
|
||
}
|
||
|
||
// 设置认证
|
||
auth := smtp.PlainAuth("", cfg.Username, cfg.Password, cfg.Endpoint)
|
||
if err := client.Auth(auth); err != nil {
|
||
client.Close()
|
||
fmt.Println("认证失败: ", err)
|
||
return err
|
||
}
|
||
|
||
// 设置发件人和收件人
|
||
err = client.Mail(cfg.FromAddress)
|
||
if err != nil {
|
||
client.Close()
|
||
fmt.Println("发件人设置失败: ", err)
|
||
return err
|
||
}
|
||
err = client.Rcpt(to)
|
||
if err != nil {
|
||
fmt.Println("发件人设置失败: ", err)
|
||
client.Close()
|
||
return err
|
||
}
|
||
|
||
// 创建一个写入SMTP服务器的标准写入器
|
||
writer, err := client.Data()
|
||
if err != nil {
|
||
client.Close()
|
||
return err
|
||
}
|
||
defer writer.Close()
|
||
|
||
// 构建邮件正文
|
||
mailBody := "From: " + cfg.FromName + "<" + cfg.FromAddress + ">\n"
|
||
mailBody += "To: " + to + "\n"
|
||
mailBody += "Subject: " + subject + "\n\n"
|
||
|
||
// 执行模板,将结果写入邮件正文
|
||
var buf bytes.Buffer
|
||
err = tmpl.Execute(&buf, args)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
mailBody += buf.String()
|
||
|
||
// 将邮件正文发送到SMTP服务器
|
||
if _, err := writer.Write([]byte(mailBody)); err != nil {
|
||
client.Close()
|
||
fmt.Printf("写入邮件内容失败: %v", err)
|
||
return err
|
||
}
|
||
|
||
if err := writer.Close(); err != nil {
|
||
client.Close()
|
||
fmt.Printf("关闭数据流失败: %v", err)
|
||
return err
|
||
}
|
||
return nil
|
||
}
|