完善日程提醒功能
This commit is contained in:
@@ -117,6 +117,100 @@ func SendTestEmailSMTP(cfg SMTPConfig, to string) error {
|
||||
return client.Quit()
|
||||
}
|
||||
|
||||
// SendHTMLEmailSMTP 发送一封 HTML 格式邮件
|
||||
func SendHTMLEmailSMTP(cfg SMTPConfig, to string, subject string, htmlBody string) error {
|
||||
to = strings.TrimSpace(to)
|
||||
if to == "" {
|
||||
return fmt.Errorf("收件人不能为空")
|
||||
}
|
||||
if cfg.Host == "" || cfg.FromAddress == "" {
|
||||
return fmt.Errorf("SMTP 主机或发件人不能为空")
|
||||
}
|
||||
if cfg.Port == 0 {
|
||||
cfg.Port = 465
|
||||
}
|
||||
timeout := cfg.Timeout
|
||||
if timeout == 0 {
|
||||
timeout = 30
|
||||
}
|
||||
d := net.Dialer{Timeout: time.Duration(timeout) * time.Second}
|
||||
addr := net.JoinHostPort(cfg.Host, strconv.FormatUint(uint64(cfg.Port), 10))
|
||||
enc := strings.ToLower(strings.TrimSpace(cfg.Encryption))
|
||||
if enc == "" {
|
||||
enc = "ssl"
|
||||
}
|
||||
|
||||
var client *smtp.Client
|
||||
var err error
|
||||
|
||||
switch enc {
|
||||
case "ssl":
|
||||
conn, derr := tls.DialWithDialer(&d, "tcp", addr, &tls.Config{ServerName: cfg.Host, MinVersion: tls.VersionTLS12})
|
||||
if derr != nil {
|
||||
return fmt.Errorf("连接 SMTP 失败: %w", derr)
|
||||
}
|
||||
defer conn.Close()
|
||||
client, err = smtp.NewClient(conn, cfg.Host)
|
||||
if err != nil {
|
||||
return fmt.Errorf("SMTP 握手失败: %w", err)
|
||||
}
|
||||
case "tls":
|
||||
conn, derr := d.Dial("tcp", addr)
|
||||
if derr != nil {
|
||||
return fmt.Errorf("连接 SMTP 失败: %w", derr)
|
||||
}
|
||||
defer conn.Close()
|
||||
client, err = smtp.NewClient(conn, cfg.Host)
|
||||
if err != nil {
|
||||
return fmt.Errorf("SMTP 握手失败: %w", err)
|
||||
}
|
||||
if ok, _ := client.Extension("STARTTLS"); ok {
|
||||
if err = client.StartTLS(&tls.Config{ServerName: cfg.Host, MinVersion: tls.VersionTLS12}); err != nil {
|
||||
_ = client.Close()
|
||||
return fmt.Errorf("STARTTLS 失败: %w", err)
|
||||
}
|
||||
}
|
||||
case "none":
|
||||
conn, derr := d.Dial("tcp", addr)
|
||||
if derr != nil {
|
||||
return fmt.Errorf("连接 SMTP 失败: %w", derr)
|
||||
}
|
||||
defer conn.Close()
|
||||
client, err = smtp.NewClient(conn, cfg.Host)
|
||||
if err != nil {
|
||||
return fmt.Errorf("SMTP 握手失败: %w", err)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("不支持的加密方式: %s", cfg.Encryption)
|
||||
}
|
||||
defer func() { _ = client.Close() }()
|
||||
|
||||
auth := smtp.PlainAuth("", cfg.FromAddress, cfg.Password, cfg.Host)
|
||||
if err = client.Auth(auth); err != nil {
|
||||
return fmt.Errorf("SMTP 认证失败: %w", err)
|
||||
}
|
||||
if err = client.Mail(cfg.FromAddress); err != nil {
|
||||
return fmt.Errorf("MAIL FROM 失败: %w", err)
|
||||
}
|
||||
if err = client.Rcpt(to); err != nil {
|
||||
return fmt.Errorf("RCPT TO 失败: %w", err)
|
||||
}
|
||||
wc, err := client.Data()
|
||||
if err != nil {
|
||||
return fmt.Errorf("DATA 失败: %w", err)
|
||||
}
|
||||
fromName := strings.TrimSpace(cfg.FromName)
|
||||
headers := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\nContent-Type: text/html; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\n",
|
||||
formatFromHeader(fromName, cfg.FromAddress), to, subject)
|
||||
if _, err = wc.Write([]byte(headers + htmlBody)); err != nil {
|
||||
return fmt.Errorf("写入邮件内容失败: %w", err)
|
||||
}
|
||||
if err = wc.Close(); err != nil {
|
||||
return fmt.Errorf("结束 DATA 失败: %w", err)
|
||||
}
|
||||
return client.Quit()
|
||||
}
|
||||
|
||||
func formatFromHeader(name, addr string) string {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
|
||||
Reference in New Issue
Block a user