Files
SproutGate/sproutgate-backend/internal/email/mailer.go
2026-03-18 22:06:43 +08:00

168 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package email
import (
"bytes"
"crypto/tls"
"fmt"
"mime"
"net/smtp"
"strings"
"time"
"sproutgate-backend/internal/storage"
)
func SendVerificationEmail(cfg storage.EmailConfig, to string, code string, expiresIn time.Duration) error {
if strings.TrimSpace(to) == "" {
return fmt.Errorf("email is required")
}
fromName := strings.TrimSpace(cfg.FromName)
if fromName == "" {
fromName = "萌芽账户认证中心"
}
fromAddress := strings.TrimSpace(cfg.FromAddress)
if fromAddress == "" {
return fmt.Errorf("from address is required")
}
username := strings.TrimSpace(cfg.Username)
if username == "" {
username = fromAddress
}
subject := "萌芽账户认证中心 - 邮箱验证"
encodedName := mime.QEncoding.Encode("UTF-8", fromName)
fromHeader := fmt.Sprintf("%s <%s>", encodedName, fromAddress)
body := fmt.Sprintf("您的验证码是:%s\n有效期%d 分钟\n\n如非本人操作请忽略此邮件。",
code, int(expiresIn.Minutes()))
var msg bytes.Buffer
msg.WriteString("From: " + fromHeader + "\r\n")
msg.WriteString("To: " + to + "\r\n")
msg.WriteString("Subject: " + mime.QEncoding.Encode("UTF-8", subject) + "\r\n")
msg.WriteString("MIME-Version: 1.0\r\n")
msg.WriteString("Content-Type: text/plain; charset=\"UTF-8\"\r\n")
msg.WriteString("Content-Transfer-Encoding: 8bit\r\n")
msg.WriteString("\r\n")
msg.WriteString(body)
addr := fmt.Sprintf("%s:%d", cfg.SMTPHost, cfg.SMTPPort)
auth := smtp.PlainAuth("", username, cfg.Password, cfg.SMTPHost)
encryption := strings.ToUpper(strings.TrimSpace(cfg.Encryption))
if cfg.SMTPPort == 465 || encryption == "SSL" {
tlsConfig := &tls.Config{
ServerName: cfg.SMTPHost,
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: false,
}
conn, err := tls.Dial("tcp", addr, tlsConfig)
if err != nil {
return err
}
client, err := smtp.NewClient(conn, cfg.SMTPHost)
if err != nil {
return err
}
defer client.Close()
if err := client.Auth(auth); err != nil {
return err
}
if err := client.Mail(fromAddress); err != nil {
return err
}
if err := client.Rcpt(to); err != nil {
return err
}
writer, err := client.Data()
if err != nil {
return err
}
if _, err := writer.Write(msg.Bytes()); err != nil {
return err
}
if err := writer.Close(); err != nil {
return err
}
return client.Quit()
}
return smtp.SendMail(addr, auth, fromAddress, []string{to}, msg.Bytes())
}
func SendResetPasswordEmail(cfg storage.EmailConfig, to string, code string, expiresIn time.Duration) error {
if strings.TrimSpace(to) == "" {
return fmt.Errorf("email is required")
}
fromName := strings.TrimSpace(cfg.FromName)
if fromName == "" {
fromName = "萌芽账户认证中心"
}
fromAddress := strings.TrimSpace(cfg.FromAddress)
if fromAddress == "" {
return fmt.Errorf("from address is required")
}
username := strings.TrimSpace(cfg.Username)
if username == "" {
username = fromAddress
}
subject := "萌芽账户认证中心 - 重置密码"
encodedName := mime.QEncoding.Encode("UTF-8", fromName)
fromHeader := fmt.Sprintf("%s <%s>", encodedName, fromAddress)
body := fmt.Sprintf("您的重置密码验证码是:%s\n有效期%d 分钟\n\n如非本人操作请忽略此邮件。",
code, int(expiresIn.Minutes()))
var msg bytes.Buffer
msg.WriteString("From: " + fromHeader + "\r\n")
msg.WriteString("To: " + to + "\r\n")
msg.WriteString("Subject: " + mime.QEncoding.Encode("UTF-8", subject) + "\r\n")
msg.WriteString("MIME-Version: 1.0\r\n")
msg.WriteString("Content-Type: text/plain; charset=\"UTF-8\"\r\n")
msg.WriteString("Content-Transfer-Encoding: 8bit\r\n")
msg.WriteString("\r\n")
msg.WriteString(body)
addr := fmt.Sprintf("%s:%d", cfg.SMTPHost, cfg.SMTPPort)
auth := smtp.PlainAuth("", username, cfg.Password, cfg.SMTPHost)
encryption := strings.ToUpper(strings.TrimSpace(cfg.Encryption))
if cfg.SMTPPort == 465 || encryption == "SSL" {
tlsConfig := &tls.Config{
ServerName: cfg.SMTPHost,
MinVersion: tls.VersionTLS12,
InsecureSkipVerify: false,
}
conn, err := tls.Dial("tcp", addr, tlsConfig)
if err != nil {
return err
}
client, err := smtp.NewClient(conn, cfg.SMTPHost)
if err != nil {
return err
}
defer client.Close()
if err := client.Auth(auth); err != nil {
return err
}
if err := client.Mail(fromAddress); err != nil {
return err
}
if err := client.Rcpt(to); err != nil {
return err
}
writer, err := client.Data()
if err != nil {
return err
}
if _, err := writer.Write(msg.Bytes()); err != nil {
return err
}
if err := writer.Close(); err != nil {
return err
}
return client.Quit()
}
return smtp.SendMail(addr, auth, fromAddress, []string{to}, msg.Bytes())
}