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 }