chore: 初始提交 Fonu 1.0.2
- 公网反代:Nginx 状态卡片(版本 / 运行状态 / 配置校验 / 端口监听) - 部署设置第一、二梯队(HTTPS 开关、安全头、限流、连接数、仅中国大陆 IP) - 隧道检测兼容 frps v0.68 / v0.71(V2 与旧版端点) - 恢复被清空的 internal/frp/store.go、internal/api/ddns_handler.go、web/src/views/DdnsView.vue
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/smtp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func SendEmail(cfg RuntimeConfig, title, message string) error {
|
||||
if strings.TrimSpace(cfg.Email.Host) == "" {
|
||||
return fmt.Errorf("SMTP 主机未配置")
|
||||
}
|
||||
if len(cfg.Email.To) == 0 {
|
||||
return fmt.Errorf("收件人未配置")
|
||||
}
|
||||
if strings.TrimSpace(cfg.SMTPPassword) == "" && strings.TrimSpace(cfg.Email.Username) != "" {
|
||||
return fmt.Errorf("SMTP 密码未配置")
|
||||
}
|
||||
|
||||
from := strings.TrimSpace(cfg.Email.From)
|
||||
if from == "" {
|
||||
from = strings.TrimSpace(cfg.Email.Username)
|
||||
}
|
||||
if from == "" {
|
||||
return fmt.Errorf("发件人未配置")
|
||||
}
|
||||
|
||||
body := buildMailBody(from, cfg.Email.To, title, message)
|
||||
addr := fmt.Sprintf("%s:%d", cfg.Email.Host, cfg.Email.Port)
|
||||
auth := smtp.PlainAuth("", cfg.Email.Username, cfg.SMTPPassword, cfg.Email.Host)
|
||||
|
||||
if cfg.Email.Port == 465 {
|
||||
return sendSMTPS(addr, cfg.Email.Host, auth, from, cfg.Email.To, body)
|
||||
}
|
||||
return smtp.SendMail(addr, auth, from, cfg.Email.To, body)
|
||||
}
|
||||
|
||||
func buildMailBody(from string, to []string, title, message string) []byte {
|
||||
headers := []string{
|
||||
"From: " + from,
|
||||
"To: " + strings.Join(to, ", "),
|
||||
"Subject: " + title,
|
||||
"MIME-Version: 1.0",
|
||||
"Content-Type: text/plain; charset=UTF-8",
|
||||
}
|
||||
bodyText := strings.TrimSpace(message)
|
||||
if bodyText == "" {
|
||||
bodyText = title
|
||||
}
|
||||
return []byte(strings.Join(headers, "\r\n") + "\r\n\r\n" + bodyText + "\r\n")
|
||||
}
|
||||
|
||||
func sendSMTPS(addr, host string, auth smtp.Auth, from string, to []string, body []byte) error {
|
||||
tlsCfg := &tls.Config{ServerName: host}
|
||||
conn, err := tls.Dial("tcp", addr, tlsCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := smtp.NewClient(conn, host)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
if auth != nil {
|
||||
if err := client.Auth(auth); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := client.Mail(from); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, rcpt := range to {
|
||||
if err := client.Rcpt(strings.TrimSpace(rcpt)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
writer, err := client.Data()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := writer.Write(body); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := writer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return client.Quit()
|
||||
}
|
||||
Reference in New Issue
Block a user