smtp支持ssl
This commit is contained in:
@@ -7,6 +7,7 @@ type EmialConfigDataMailgun struct {
|
||||
}
|
||||
|
||||
type EmailConfigDataSmtp struct {
|
||||
IsSSL bool `json:"is_ssl"` // 是否SSL
|
||||
Username string `json:"username"` // 邮箱账号
|
||||
Password string `json:"password"` // 授权码
|
||||
Host string `json:"host"` // SMTP 服务器【默认smtpdm.aliyun.com】
|
||||
|
||||
+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 := ""
|
||||
|
||||
+31
-17
@@ -3,8 +3,6 @@ package smtp_test
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.yun.ink/pkg/mailx/interfaces"
|
||||
@@ -15,35 +13,51 @@ func TestMail(t *testing.T) {
|
||||
sm := smtp.NewSmtp()
|
||||
ctx := context.Background()
|
||||
|
||||
// ini, err := sm.SetOption(ctx, interfaces.SetSmtp(&interfaces.EmailConfigDataSmtp{
|
||||
// Username: "support@email.blueoceanpay.com",
|
||||
// Password: "SupporT2017",
|
||||
// ReplyTo: "",
|
||||
// Host: "smtpdm-ap-southeast-1.aliyun.com",
|
||||
// Port: "80",
|
||||
// }))
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
|
||||
ini, err := sm.SetOption(ctx, interfaces.SetSmtp(&interfaces.EmailConfigDataSmtp{
|
||||
Username: "support@email.blueoceanpay.com",
|
||||
Password: "SupporT2017",
|
||||
IsSSL: true,
|
||||
Username: "demo@yunink.net",
|
||||
Password: "aAhVPzHydLoc9Fj8",
|
||||
ReplyTo: "",
|
||||
Host: "smtpdm-ap-southeast-1.aliyun.com",
|
||||
Port: "80",
|
||||
Host: "smtp.exmail.qq.com",
|
||||
Port: "465",
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
req, err := http.Get("https://baidu.com")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
|
||||
by, err := io.ReadAll(req.Body)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// req, err := http.Get("https://baidu.com")
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// defer req.Body.Close()
|
||||
|
||||
// by, err := io.ReadAll(req.Body)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
|
||||
msg := interfaces.Message{
|
||||
Form: "demo@yunink.net",
|
||||
To: []string{"995116474@qq.com"},
|
||||
Cc: []string{"287852692@qq.com"},
|
||||
Bcc: []string{"1362716835@qq.com"},
|
||||
ReplyTo: "huangxinyun@dreaminglife.cn",
|
||||
Subject: "test mail",
|
||||
Body: string(by),
|
||||
Subject: "测试邮件",
|
||||
Body: "这是测试邮件", //string(by),
|
||||
Attachment: []interfaces.MessageAttachment{
|
||||
// {
|
||||
// Name: "/code/statistic/out.xlsx",
|
||||
|
||||
Reference in New Issue
Block a user