This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,279 @@
//go:build plus
package mediasenders
import (
"crypto/tls"
"encoding/base64"
"errors"
teaconst "github.com/TeaOSLab/EdgeAPI/internal/const"
"net"
"net/mail"
"net/smtp"
"strconv"
"time"
)
type MailInfo struct {
To string
Subject string
Body string
}
// EmailMedia 邮件媒介
type EmailMedia struct {
SMTP string `yaml:"smtp" json:"smtp"` // SMTP地址host:port
Username string `yaml:"username" json:"username"` // 用户名
Password string `yaml:"password" json:"password"` // 密码
From string `yaml:"from" json:"from"` // 发件人
FromName string `yaml:"fromName" json:"fromName"` // 发件人名称
Protocol string `yaml:"protocol" json:"protocol"` // 协议tcp/tls
}
// NewEmailMedia 获取新对象
func NewEmailMedia() *EmailMedia {
return &EmailMedia{}
}
func (this *EmailMedia) Send(user string, subject string, body string, productName string, datetime string) (resp []byte, err error) {
if len(this.SMTP) == 0 {
return nil, errors.New("host address should be specified")
}
// 自动加端口
if _, _, err := net.SplitHostPort(this.SMTP); err != nil {
this.SMTP += ":587"
}
if len(this.From) == 0 {
this.From = this.Username
}
var contentType = "Content-Type: text/html; charset=UTF-8"
var senderName = this.FromName
if len(senderName) == 0 {
if len(productName) > 0 {
senderName = productName
} else {
senderName = teaconst.GlobalProductName
}
subject = "[" + senderName + "]" + subject
}
var msg = []byte("To: " + user + "\r\nFrom: " + strconv.Quote(senderName) + " <" + this.From + ">\r\nSubject: " + "=?utf-8?B?" + base64.StdEncoding.EncodeToString([]byte(subject)) + "?=" + "\r\n" + contentType + "\r\n\r\n" + body)
return nil, this.SendMail(this.From, []string{user}, msg)
}
// RequireUser 是否需要用户标识
func (this *EmailMedia) RequireUser() bool {
return true
}
// SendMail 发送邮件
func (this *EmailMedia) SendMail(from string, to []string, message []byte) error {
_, err := mail.ParseAddress(from)
if err != nil {
return err
}
if len(to) == 0 {
return errors.New("recipients should not be empty")
}
for _, to1 := range to {
_, err := mail.ParseAddress(to1)
if err != nil {
return err
}
}
client, err := this.Connect()
if err != nil {
return err
}
defer func() {
_ = client.Quit()
_ = client.Close()
}()
// To && From
if err := client.Mail(from); err != nil {
return err
}
for _, to1 := range to {
if err := client.Rcpt(to1); err != nil {
return err
}
}
// Data
w, err := client.Data()
if err != nil {
return err
}
_, err = w.Write(message)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return nil
}
// SendMails 发送邮件
func (this *EmailMedia) SendMails(mails []*MailInfo, productName string) error {
if len(mails) == 0 {
return nil
}
_, err := mail.ParseAddress(this.From)
if err != nil {
return err
}
client, err := this.Connect()
if err != nil {
return err
}
defer func() {
_ = client.Quit()
_ = client.Close()
}()
// 发送者
var senderName = this.FromName
if len(senderName) == 0 {
if len(productName) > 0 {
senderName = productName
} else {
senderName = teaconst.GlobalProductName
}
}
// 创建邮件
for _, mailInfo := range mails {
if len(mailInfo.To) == 0 {
continue
}
_, err = mail.ParseAddress(mailInfo.To)
if err != nil {
return err
}
if err := client.Mail(this.From); err != nil {
return err
}
if err := client.Rcpt(mailInfo.To); err != nil {
return err
}
// Data
w, err := client.Data()
if err != nil {
return err
}
_, err = w.Write([]byte("To: " + mailInfo.To + "\r\nFrom: " + strconv.Quote(senderName) + " <" + this.From + ">\r\nSubject: " + mailInfo.Subject + "\r\n" + "Content-Type: text/html; charset=UTF-8" + "\r\n\r\n" + mailInfo.Body))
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
}
return nil
}
func (this *EmailMedia) Connect() (*smtp.Client, error) {
var serverName = this.SMTP
var username = this.Username
var password = this.Password
host, port, _ := net.SplitHostPort(serverName)
var client *smtp.Client
// TLS config
var tlsConfig = &tls.Config{
InsecureSkipVerify: true,
ServerName: host,
}
if this.Protocol == "tcp" || (len(this.Protocol) == 0 && port == "25") { // 25 port: default tcp port
conn, err := net.DialTimeout("tcp", serverName, 10*time.Second)
if err != nil {
return nil, err
}
client, err = smtp.NewClient(conn, host)
if err != nil {
return nil, err
}
} else if port == "587" { // 587 port: prefer START_TLS
conn, err := net.DialTimeout("tcp", serverName, 10*time.Second)
if err != nil {
conn, err := tls.Dial("tcp", serverName, tlsConfig)
if err != nil {
return nil, err
}
client, err = smtp.NewClient(conn, host)
if err != nil {
return nil, err
}
} else {
client, err = smtp.NewClient(conn, host)
if err != nil {
return nil, err
}
err = client.StartTLS(tlsConfig)
if err != nil {
return nil, err
}
}
} else {
conn, err := tls.Dial("tcp", serverName, tlsConfig)
if err != nil {
conn, err := net.DialTimeout("tcp", serverName, 10*time.Second)
if err != nil {
return nil, err
}
client, err = smtp.NewClient(conn, host)
if err != nil {
return nil, err
}
err = client.StartTLS(tlsConfig)
if err != nil {
return nil, err
}
} else {
client, err = smtp.NewClient(conn, host)
if err != nil {
return nil, err
}
}
}
// 认证
var auth = smtp.PlainAuth("", username, password, host)
if err := client.Auth(auth); err != nil {
_ = client.Quit()
_ = client.Close()
return nil, err
}
return client, nil
}