10044b474f
- 添加HTTP客户端工具支持GET/POST请求 - 添加SMTP邮件发送功能 - 添加数据库操作(db.getRecords, db.deleteRecord, db.deleteRecords) - 添加订单管理云端函数(读取、接收、筛选、成功、失败) - 添加测试推送和邮件通知云端函数 - 修复云端函数编辑页面预览代码换行显示 - 云端变量数据模型重构(合并数据类型)
163 lines
3.4 KiB
Go
163 lines
3.4 KiB
Go
package smtputil
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"net/smtp"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type SMTPConfig struct {
|
|
Host string
|
|
Port int
|
|
Username string
|
|
Password string
|
|
From string
|
|
UseTLS bool
|
|
}
|
|
|
|
type EmailMessage struct {
|
|
To []string
|
|
Subject string
|
|
Body string
|
|
HTML bool
|
|
}
|
|
|
|
type SMTPResult struct {
|
|
Success bool `json:"success"`
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
type SMTPClient struct {
|
|
config SMTPConfig
|
|
timeout time.Duration
|
|
}
|
|
|
|
func NewSMTPClient(config SMTPConfig, timeout time.Duration) *SMTPClient {
|
|
if timeout <= 0 {
|
|
timeout = 30 * time.Second
|
|
}
|
|
return &SMTPClient{
|
|
config: config,
|
|
timeout: timeout,
|
|
}
|
|
}
|
|
|
|
func (c *SMTPClient) Send(msg EmailMessage) *SMTPResult {
|
|
result := &SMTPResult{Success: false}
|
|
|
|
if len(msg.To) == 0 {
|
|
result.Error = "收件人不能为空"
|
|
return result
|
|
}
|
|
|
|
if c.config.Host == "" {
|
|
result.Error = "SMTP服务器地址不能为空"
|
|
return result
|
|
}
|
|
|
|
addr := fmt.Sprintf("%s:%d", c.config.Host, c.config.Port)
|
|
|
|
var auth smtp.Auth
|
|
if c.config.Username != "" && c.config.Password != "" {
|
|
auth = smtp.PlainAuth("", c.config.Username, c.config.Password, c.config.Host)
|
|
}
|
|
|
|
from := c.config.From
|
|
if from == "" {
|
|
from = c.config.Username
|
|
}
|
|
|
|
contentType := "text/plain"
|
|
if msg.HTML {
|
|
contentType = "text/html"
|
|
}
|
|
|
|
headers := make(map[string]string)
|
|
headers["From"] = from
|
|
headers["To"] = strings.Join(msg.To, ", ")
|
|
headers["Subject"] = msg.Subject
|
|
headers["MIME-Version"] = "1.0"
|
|
headers["Content-Type"] = fmt.Sprintf("%s; charset=UTF-8", contentType)
|
|
headers["Date"] = time.Now().Format(time.RFC1123Z)
|
|
|
|
var message strings.Builder
|
|
for k, v := range headers {
|
|
message.WriteString(fmt.Sprintf("%s: %s\r\n", k, v))
|
|
}
|
|
message.WriteString("\r\n")
|
|
message.WriteString(msg.Body)
|
|
|
|
if c.config.UseTLS {
|
|
tlsConfig := &tls.Config{
|
|
InsecureSkipVerify: false,
|
|
ServerName: c.config.Host,
|
|
}
|
|
|
|
conn, err := tls.Dial("tcp", addr, tlsConfig)
|
|
if err != nil {
|
|
result.Error = fmt.Sprintf("TLS连接失败: %v", err)
|
|
return result
|
|
}
|
|
defer conn.Close()
|
|
|
|
client, err := smtp.NewClient(conn, c.config.Host)
|
|
if err != nil {
|
|
result.Error = fmt.Sprintf("创建SMTP客户端失败: %v", err)
|
|
return result
|
|
}
|
|
defer client.Close()
|
|
|
|
if auth != nil {
|
|
if err := client.Auth(auth); err != nil {
|
|
result.Error = fmt.Sprintf("SMTP认证失败: %v", err)
|
|
return result
|
|
}
|
|
}
|
|
|
|
if err := client.Mail(from); err != nil {
|
|
result.Error = fmt.Sprintf("设置发件人失败: %v", err)
|
|
return result
|
|
}
|
|
|
|
for _, to := range msg.To {
|
|
if err := client.Rcpt(to); err != nil {
|
|
result.Error = fmt.Sprintf("设置收件人失败: %v", err)
|
|
return result
|
|
}
|
|
}
|
|
|
|
w, err := client.Data()
|
|
if err != nil {
|
|
result.Error = fmt.Sprintf("准备邮件数据失败: %v", err)
|
|
return result
|
|
}
|
|
|
|
_, err = w.Write([]byte(message.String()))
|
|
if err != nil {
|
|
result.Error = fmt.Sprintf("写入邮件内容失败: %v", err)
|
|
return result
|
|
}
|
|
|
|
if err := w.Close(); err != nil {
|
|
result.Error = fmt.Sprintf("关闭邮件写入失败: %v", err)
|
|
return result
|
|
}
|
|
|
|
if err := client.Quit(); err != nil {
|
|
result.Error = fmt.Sprintf("关闭SMTP连接失败: %v", err)
|
|
return result
|
|
}
|
|
} else {
|
|
err := smtp.SendMail(addr, auth, from, msg.To, []byte(message.String()))
|
|
if err != nil {
|
|
result.Error = fmt.Sprintf("发送邮件失败: %v", err)
|
|
return result
|
|
}
|
|
}
|
|
|
|
result.Success = true
|
|
return result
|
|
}
|