Files
full/module/base/sender/internal/logic/mail/send.go

153 lines
3.4 KiB
Go
Raw Normal View History

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
}