smtp支持ssl
This commit is contained in:
+83
-1
@@ -3,6 +3,7 @@ package smtp
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -45,7 +46,6 @@ func (l *Smtp) SetOption(ctx context.Context, opt ...interfaces.Option) (interfa
|
||||
return nil, errors.New("not smtp")
|
||||
}
|
||||
|
||||
l.auth = smtp.PlainAuth("", l.Options.Smtp.Username, l.Options.Smtp.Password, l.Options.Smtp.Host)
|
||||
return l, nil
|
||||
}
|
||||
|
||||
@@ -53,6 +53,16 @@ func (l *Smtp) Send(ctx context.Context, message interfaces.Message) error {
|
||||
if l.Options.Smtp == nil {
|
||||
return errors.New("not init")
|
||||
}
|
||||
|
||||
if l.Options.Smtp.IsSSL {
|
||||
//
|
||||
return l.SendSSL(ctx, message)
|
||||
}
|
||||
return l.SendPlain(ctx, message)
|
||||
}
|
||||
|
||||
// 明文
|
||||
func (l *Smtp) SendPlain(ctx context.Context, message interfaces.Message) error {
|
||||
// .Auth()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
boundary := "YunBoundaryYun"
|
||||
@@ -148,10 +158,82 @@ func (l *Smtp) Send(ctx context.Context, message interfaces.Message) error {
|
||||
|
||||
buffer.WriteString("\r\n--" + boundary + "--\r\n")
|
||||
b := buffer.Bytes()
|
||||
l.auth = smtp.PlainAuth("", l.Options.Smtp.Username, l.Options.Smtp.Password, l.Options.Smtp.Host)
|
||||
err := smtp.SendMail(l.Options.Smtp.Host+":"+l.Options.Smtp.Port, l.auth, l.Options.Smtp.Username, message.To, b)
|
||||
return err
|
||||
}
|
||||
|
||||
// SSL
|
||||
func (l *Smtp) SendSSL(ctx context.Context, message interfaces.Message) error {
|
||||
|
||||
// 邮件内容格式(必须符合SMTP协议规范)
|
||||
contentType := "Content-Type: text/html; charset=UTF-8"
|
||||
msg := []byte("To: " + message.To[0] + "\r\n" +
|
||||
"From: " + message.Form + "\r\n" +
|
||||
"Subject: " + message.Subject + "\r\n" +
|
||||
contentType + "\r\n\r\n" +
|
||||
message.Body)
|
||||
|
||||
// 解析收件人(支持多个)
|
||||
// toList := strings.Split(message.To, ",")
|
||||
|
||||
// 1. 建立TCP连接(SSL通常用465端口)
|
||||
if l.Options.Smtp.Port == "" {
|
||||
l.Options.Smtp.Port = "465"
|
||||
}
|
||||
host := l.Options.Smtp.Host + ":" + l.Options.Smtp.Port
|
||||
|
||||
conn, err := tls.Dial("tcp", host, &tls.Config{
|
||||
InsecureSkipVerify: false, // 生产环境不建议跳过证书验证
|
||||
ServerName: strings.Split(host, ":")[0], // 服务器域名(用于证书验证)
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接服务器失败: %v", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
// 2. 创建SMTP客户端
|
||||
client, err := smtp.NewClient(conn, strings.Split(host, ":")[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建SMTP客户端失败: %v", err)
|
||||
}
|
||||
|
||||
// 3. 身份验证(使用登录邮箱和授权码)
|
||||
auth := smtp.PlainAuth("", l.Options.Smtp.Username, l.Options.Smtp.Password, strings.Split(host, ":")[0])
|
||||
if err := client.Auth(auth); err != nil {
|
||||
return fmt.Errorf("身份验证失败: %v", err)
|
||||
}
|
||||
|
||||
// 4. 设置发件人
|
||||
if err := client.Mail(l.Options.Smtp.Username); err != nil {
|
||||
return fmt.Errorf("设置发件人失败: %v", err)
|
||||
}
|
||||
|
||||
// 5. 设置收件人(支持多个)
|
||||
for _, addr := range message.To {
|
||||
if err := client.Rcpt(addr); err != nil {
|
||||
return fmt.Errorf("设置收件人 %s 失败: %v", addr, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 发送邮件内容
|
||||
w, err := client.Data()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取数据写入流失败: %v", err)
|
||||
}
|
||||
_, err = w.Write(msg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("写入邮件内容失败: %v", err)
|
||||
}
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return fmt.Errorf("关闭写入流失败: %v", err)
|
||||
}
|
||||
|
||||
// 7. 退出SMTP会话
|
||||
return client.Quit()
|
||||
}
|
||||
|
||||
// 格式化header
|
||||
func (l *Smtp) writeHeader(buffer *bytes.Buffer, Header map[string]string) string {
|
||||
header := ""
|
||||
|
||||
Reference in New Issue
Block a user