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
}

注意事项

  1. 默认会检查重复的收件人地址,从v2.13.0开始可以使用email.AllowDuplicateAddress = true跳过检查
  2. 默认Bcc头不会出现在邮件中,从v2.14.0开始可以使用email.AddBccToHeader = true添加
  3. 默认会验证地址是否符合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)
}

性能优化建议

  1. 连接复用:启用KeepAlive并合理设置连接池大小
  2. 超时设置:根据网络状况调整连接和发送超时
  3. 批量发送:使用goroutine并发发送,但注意不要超过SMTP服务器的限制
  4. 错误处理:实现重试机制处理临时性错误

错误处理

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库,通过合理配置和优化,可以满足大多数邮件发送需求,特别是在需要高效发送大量邮件的场景下。

回到顶部