From b584b4bfb6faa46668b76687895626fa6de9061c Mon Sep 17 00:00:00 2001 From: RockYang Date: Fri, 19 Apr 2024 12:04:59 +0800 Subject: [PATCH] support send email use TLS --- api/core/types/config.go | 1 + api/service/smtp_sms_service.go | 88 +++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/api/core/types/config.go b/api/core/types/config.go index 24a94e78..850dd670 100644 --- a/api/core/types/config.go +++ b/api/core/types/config.go @@ -30,6 +30,7 @@ type AppConfig struct { } type SmtpConfig struct { + UseTls bool // 是否使用 TLS 发送 Host string Port int AppName string // 应用名称 diff --git a/api/service/smtp_sms_service.go b/api/service/smtp_sms_service.go index fe094d49..256de934 100644 --- a/api/service/smtp_sms_service.go +++ b/api/service/smtp_sms_service.go @@ -3,9 +3,11 @@ package service import ( "bytes" "chatplus/core/types" + "crypto/tls" "fmt" "mime" "net/smtp" + "net/textproto" ) type SmtpService struct { @@ -19,12 +21,18 @@ func NewSmtpService(appConfig *types.AppConfig) *SmtpService { } func (s *SmtpService) SendVerifyCode(to string, code int) error { - subject := "ChatPlus注册验证码" - body := fmt.Sprintf("您正在注册 ChatPlus AI 助手账户,注册验证码为 %d,请不要告诉他人。如非本人操作,请忽略此邮件。", code) + subject := "Geek-AI 注册验证码" + body := fmt.Sprintf("您正在注册 Geek-AI 助手账户,注册验证码为 %d,请不要告诉他人。如非本人操作,请忽略此邮件。", code) - // 设置SMTP客户端配置 auth := smtp.PlainAuth("", s.config.From, s.config.Password, s.config.Host) + if s.config.UseTls { + return s.sendTLS(auth, to, subject, body) + } else { + return s.send(auth, to, subject, body) + } +} +func (s *SmtpService) send(auth smtp.Auth, to string, subject string, body string) error { // 对主题进行MIME编码 encodedSubject := mime.QEncoding.Encode("UTF-8", subject) // 组装邮件 @@ -34,11 +42,83 @@ func (s *SmtpService) SendVerifyCode(to string, code int) error { message.WriteString(fmt.Sprintf("Subject: %s\r\n", encodedSubject)) message.WriteString("\r\n" + body) - // 发送邮件 // 发送邮件 err := smtp.SendMail(s.config.Host+":"+fmt.Sprint(s.config.Port), auth, s.config.From, []string{to}, message.Bytes()) if err != nil { return fmt.Errorf("error sending email: %v", err) } + + return err + +} + +func (s *SmtpService) sendTLS(auth smtp.Auth, to string, subject string, body string) error { + // TLS配置 + tlsConfig := &tls.Config{ + ServerName: s.config.Host, + } + + // 建立TLS连接 + conn, err := tls.Dial("tcp", fmt.Sprintf("%s:%d", s.config.Host, s.config.Port), tlsConfig) + if err != nil { + return fmt.Errorf("error connecting to SMTP server: %v", err) + } + defer conn.Close() + + client, err := smtp.NewClient(conn, s.config.Host) + if err != nil { + return fmt.Errorf("error creating SMTP client: %v", err) + } + defer client.Quit() + + // 身份验证 + if err = client.Auth(auth); err != nil { + return fmt.Errorf("error authenticating: %v", err) + } + + // 设置寄件人 + if err = client.Mail(s.config.From); err != nil { + return fmt.Errorf("error setting sender: %v", err) + } + + // 设置收件人 + if err = client.Rcpt(to); err != nil { + return fmt.Errorf("error setting recipient: %v", err) + } + + // 发送邮件内容 + wc, err := client.Data() + if err != nil { + return fmt.Errorf("error getting data writer: %v", err) + } + defer wc.Close() + + header := make(textproto.MIMEHeader) + header.Set("From", s.config.From) + header.Set("To", to) + header.Set("Subject", subject) + + // 将邮件头写入 + for key, values := range header { + for _, value := range values { + _, err = fmt.Fprintf(wc, "%s: %s\r\n", key, value) + if err != nil { + return fmt.Errorf("error sending email header: %v", err) + } + } + } + _, _ = fmt.Fprintln(wc) + // 将邮件内容写入 + _, err = fmt.Fprintf(wc, body) + if err != nil { + return fmt.Errorf("error sending email: %v", err) + } + + // 发送完毕 + err = wc.Close() + if err != nil { + return fmt.Errorf("error closing data writer: %v", err) + } + return nil }