golang实现SMTP邮件发送与保持连接的高效插件库go-simple-mail的使用
Golang实现SMTP邮件发送与保持连接的高效插件库go-simple-mail的使用
介绍
Go Simple Mail是一个简单高效的Go语言邮件发送包,支持SMTP Keep Alive和连接/发送超时功能。它是基于Joe Grasse的两个未维护的包开发而来,并进行了大量改进。
主要特性
- 支持多附件(文件路径、base64和字节)
- 支持内联附件
- 多收件人支持
- 优先级设置
- 回复地址设置
- 嵌入式图片
- HTML和文本模板
- 特殊字符自动编码
- SSL/TLS和STARTTLS支持
- 保持SMTP连接(持久连接)
- 连接和发送超时设置
- 多种认证方式(PLAIN、LOGIN、CRAM-MD5、AUTO)
- 自定义TLS配置
- 本地发送支持
- DKIM签名支持
- 使用代理的自定义连接支持
安装
使用go modules安装:
go get github.com/xhit/go-simple-mail/v2
基本使用示例
package main
import (
"log"
"time"
"crypto/tls"
mail "github.com/xhit/go-simple-mail/v2"
)
const htmlBody = `<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Hello Gophers!</title>
</head>
<body>
<p>This is the <b>Go gopher</b>.</p>
<p><img src="cid:Gopher.png" alt="Go gopher" /></p>
<p>Image created by Renee French</p>
</body>
</html>`
func main() {
server := mail.NewSMTPClient()
// SMTP服务器配置
server.Host = "smtp.example.com"
server.Port = 587
server.Username = "test@example.com"
server.Password = "examplepass"
server.Encryption = mail.EncryptionSTARTTLS
// 保持连接设置
server.KeepAlive = false
// 超时设置
server.ConnectTimeout = 10 * time.Second
server.SendTimeout = 10 * time.Second
// 自定义TLS配置(测试用)
server.TLSConfig = &tls.Config{InsecureSkipVerify: true}
// 连接SMTP服务器
smtpClient, err := server.Connect()
if err != nil {
log.Fatal(err)
}
// 创建邮件
email := mail.NewMSG()
email.SetFrom("From Example <nube@example.com>").
AddTo("xhit@example.com").
AddCc("otherto@example.com").
SetSubject("New Go Email").
SetListUnsubscribe("<mailto:unsubscribe@example.com?subject=https://example.com/unsubscribe>")
email.SetBody(mail.TextHTML, htmlBody)
// 添加内联图片
email.Attach(&mail.File{FilePath: "/path/to/image.png", Name: "Gopher.png", Inline: true})
// 发送邮件
err = email.Send(smtpClient)
if err != nil {
log.Println(err)
} else {
log.Println("Email Sent")
}
}
保持连接发送多封邮件
// 设置保持连接
server.KeepAlive = true
for _, to := range []string{
"to1@example1.com",
"to3@example2.com",
"to4@example3.com",
} {
email := mail.NewMSG()
email.SetFrom("From Example <nube@example.com>").
AddTo(to).
SetSubject("New Go Email")
email.SetBody(mail.TextHTML, htmlBody)
email.Attach(&mail.File{FilePath: "/path/to/image.png", Name: "Gopher.png", Inline: true})
if email.Error != nil {
log.Fatal(email.Error)
}
err = email.Send(smtpClient)
if err != nil {
log.Println(err)
} else {
log.Println("Email Sent")
}
}
使用代理的自定义连接
package main
import (
"crypto/tls"
"fmt"
"log"
"net"
mail "github.com/xhit/go-simple-mail/v2"
"golang.org/x/net/proxy"
)
func main() {
server := mail.NewSMTPClient()
host := "smtp.example.com"
port := 587
proxyAddr := "proxy.server"
// 获取通过代理的自定义连接
conn, err := getCustomConnWithProxy(proxyAddr, host, port)
if err != nil {
log.Fatal(err)
}
server.Username = "test@example.com"
server.Password = "examplepass"
server.Encryption = mail.EncryptionSTARTTLS
server.CustomConn = conn // 使用自定义连接
smtpClient, err := server.Connect()
if err != nil {
log.Fatal(err)
}
email := mail.NewMSG()
err = email.SetFrom("From Example <nube@example.com>").AddTo("xhit@example.com").Send(smtpClient)
if err != nil {
log.Fatal(err)
}
}
func getCustomConnWithProxy(proxyAddr, host string, port int) (net.Conn, error) {
dial, err := proxy.SOCKS5("tcp", proxyAddr, nil, proxy.Direct)
if err != nil {
return nil, err
}
dialer, err := dial.Dial("tcp", fmt.Sprintf("%s:%d", host, port))
if err != nil {
return nil, err
}
conf := &tls.Config{ServerName: host}
conn := tls.Client(dialer, conf)
return conn, nil
}
注意事项
- 默认会检查重复的收件人地址,从v2.13.0开始可以使用
email.AllowDuplicateAddress = true
跳过检查 - 默认Bcc头不会出现在邮件中,从v2.14.0开始可以使用
email.AddBccToHeader = true
添加 - 默认会验证地址是否符合RFC5322标准,设置
email.UseProvidedAddress = true
可以跳过验证
Go Simple Mail提供了丰富的功能和灵活的API,可以满足各种邮件发送需求。更多示例可以参考官方文档。
更多关于golang实现SMTP邮件发送与保持连接的高效插件库go-simple-mail的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现SMTP邮件发送与保持连接的高效插件库go-simple-mail的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用go-simple-mail实现高效SMTP邮件发送
go-simple-mail是一个简单易用的Golang SMTP邮件发送库,支持保持连接、HTML邮件、附件等功能。下面我将详细介绍如何使用这个库实现高效的邮件发送。
基本安装
首先安装go-simple-mail库:
go get github.com/xhit/go-simple-mail/v2
基本使用示例
package main
import (
"log"
"time"
mail "github.com/xhit/go-simple-mail/v2"
)
func main() {
// 创建SMTP客户端
server := mail.NewSMTPClient()
server.Host = "smtp.example.com"
server.Port = 587
server.Username = "your_username"
server.Password = "your_password"
server.Encryption = mail.EncryptionSTARTTLS
// 设置保持连接
server.KeepAlive = true // 保持连接开启
server.ConnectTimeout = 10 * time.Second
server.SendTimeout = 10 * time.Second
// 连接到SMTP服务器
smtpClient, err := server.Connect()
if err != nil {
log.Fatal(err)
}
// 创建邮件
email := mail.NewMSG()
email.SetFrom("From Me <from@example.com>")
email.AddTo("to@example.com")
email.SetSubject("Test Email")
email.SetBody(mail.TextHTML, "<h1>Hello from go-simple-mail</h1><p>This is a test email.</p>")
// 添加附件
email.Attach(&mail.File{
Name: "document.pdf",
Data: []byte("dummy pdf content"),
Inline: false,
})
// 发送邮件
err = email.Send(smtpClient)
if err != nil {
log.Println(err)
} else {
log.Println("Email Sent")
}
}
高级功能
1. 保持连接池
为了实现高效发送,可以创建连接池:
type MailPool struct {
server *mail.SMTPServer
pool chan *mail.SMTPClient
}
func NewMailPool(server *mail.SMTPServer, poolSize int) (*MailPool, error) {
pool := make(chan *mail.SMTPClient, poolSize)
for i := 0; i < poolSize; i++ {
client, err := server.Connect()
if err != nil {
return nil, err
}
pool <- client
}
return &MailPool{
server: server,
pool: pool,
}, nil
}
func (p *MailPool) Get() *mail.SMTPClient {
return <-p.pool
}
func (p *MailPool) Put(client *mail.SMTPClient) {
p.pool <- client
}
// 使用示例
func main() {
server := mail.NewSMTPClient()
// 配置server...
pool, err := NewMailPool(server, 5)
if err != nil {
log.Fatal(err)
}
// 获取连接
client := pool.Get()
defer pool.Put(client)
// 发送邮件...
}
2. 批量发送邮件
func sendBulkEmails(clients []*mail.SMTPClient, emails []*mail.Email) error {
errChan := make(chan error, len(emails))
var wg sync.WaitGroup
for i, email := range emails {
wg.Add(1)
go func(idx int, e *mail.Email, c *mail.SMTPClient) {
defer wg.Done()
if err := e.Send(c); err != nil {
errChan <- fmt.Errorf("email %d failed: %v", idx, err)
}
}(i, email, clients[i%len(clients)])
}
wg.Wait()
close(errChan)
var errors []string
for err := range errChan {
errors = append(errors, err.Error())
}
if len(errors) > 0 {
return fmt.Errorf(strings.Join(errors, "\n"))
}
return nil
}
3. 邮件模板
结合html/template实现模板邮件:
func sendTemplatedEmail(client *mail.SMTPClient, to string, data interface{}) error {
tmpl, err := template.ParseFiles("email_template.html")
if err != nil {
return err
}
var body bytes.Buffer
if err := tmpl.Execute(&body, data); err != nil {
return err
}
email := mail.NewMSG()
email.SetFrom("noreply@example.com")
email.AddTo(to)
email.SetSubject("Your Custom Email")
email.SetBody(mail.TextHTML, body.String())
return email.Send(client)
}
性能优化建议
- 连接复用:启用
KeepAlive
并合理设置连接池大小 - 超时设置:根据网络状况调整连接和发送超时
- 批量发送:使用goroutine并发发送,但注意不要超过SMTP服务器的限制
- 错误处理:实现重试机制处理临时性错误
错误处理
func sendWithRetry(email *mail.Email, client *mail.SMTPClient, maxRetries int) error {
var lastErr error
for i := 0; i < maxRetries; i++ {
if err := email.Send(client); err != nil {
lastErr = err
if isTemporaryError(err) {
time.Sleep(time.Second * time.Duration(i+1))
continue
}
return err
}
return nil
}
return fmt.Errorf("after %d retries, last error: %v", maxRetries, lastErr)
}
func isTemporaryError(err error) bool {
// 根据实际情况判断是否为临时错误
return strings.Contains(err.Error(), "timeout") ||
strings.Contains(err.Error(), "connection reset")
}
go-simple-mail是一个功能全面且易于使用的SMTP库,通过合理配置和优化,可以满足大多数邮件发送需求,特别是在需要高效发送大量邮件的场景下。