使用FakeSMTP创建本地SMTP服务器接收邮件具体实现。

以下代码来自Let's Go further节选。具体说明均为作者本人理解。

编辑邮件模版

主要包含三个template:

  1. subject:主题
  2. plainBody: 纯文本正文
  3. htmlBody:超文本语言正文
html 复制代码
{{define "subject"}}Welcome to Greenlight!{{end}}
{{define "plainBody"}}
Hi,
Thanks for signing up for a Greenlight account. We're excited to have you on board!
For future reference, your user ID number is {{.ID}}.
Thanks,
The Greenlight Team
{{end}}
{{define "htmlBody"}}
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Hi,</p>
<p>Thanks for signing up for a Greenlight account. We're excited to have you on board!</p>
<p>For future reference, your user ID number is {{.ID}}.</p>
<p>Thanks,</p>
<p>The Greenlight Team</p>
</body>
</html>
{{end}}

创建mailer.go

主要功能为解析,执行邮件模版,将邮件正文加载到bytes.Buffer中,最后打包信息发送

go 复制代码
package mailer

import (
	"bytes"
	"embed"
	"github.com/go-mail/mail/v2"
	"html/template"
	"time"
)

// 声明一个embed.FS变量存储email模板,在他上面有一个注释指令表明我们想要存储哪个文件的模板
//
/*
	1. 只能在包级别的变量上使用//go:embed指令,不能在函数或者方法中使用
	2. 路径应该相对于该指令的源代码
	3. 路径不能包含.or..,也不能以/开头或结尾,这实际上限制了你只能嵌入与源代码位于同一目录(或子目录)的文件
	4. 如果路径指向一个目录,那么会递归加载该目录下的所有文件,但是不会加载.  /开头的文件,如果需要加载,需要在路径中使用通配符//go:embed "templates/*"
	5. 可以在一个指令中指定多个目录和文件
*/

//go:embed "templates"
var templateFS embed.FS

// Mailer mail.Dialer用于连接SMTP服务器  email的发送信息,包含名字和地址"Alice Smith <[email protected]>"
type Mailer struct {
	dialer *mail.Dialer
	sender string
}

func New(host string, port int, username, password, sender string) Mailer {
	//使用SMTP服务器的配置初始化一个mail.Dialer实例,发送邮件时使用五秒的超时配置
	dialer := mail.NewDialer(host, port, username, password)
	dialer.Timeout = 5 * time.Second

	return Mailer{
		dialer: dialer,
		sender: sender,
	}
}

// Send
//
//	@Description:
//	@receiver m
//	@param recipient  接受者邮件地址
//	@param templateFile 模版文件名
//	@param data 模板的动态数据
//	@return error
func (m *Mailer) Send(recipient, templateFile string, data interface{}) error {
	//1. 解析模板 从embed文件系统解析请求模板
	parseFS, err := template.New("email").ParseFS(templateFS, "templates/"+templateFile)
	if err != nil {
		return err
	}
	//2. 执行模版 执行模板文件,将参数传递进去,将结果存储在bytes.Buffer变量中
	subject := new(bytes.Buffer)
	err = parseFS.ExecuteTemplate(subject, "subject", data)
	if err != nil {
		return err
	}
	plainBody := new(bytes.Buffer)
	err = parseFS.ExecuteTemplate(plainBody, "plainBody", data)
	if err != nil {
		return err
	}
	htmlBody := new(bytes.Buffer)
	err = parseFS.ExecuteTemplate(htmlBody, "htmlBody", data)
	if err != nil {
		return err
	}
	//设置邮件具体内容
	message := mail.NewMessage()
	message.SetHeader("To", recipient) //设置邮件头信息
	message.SetHeader("From", m.sender)
	message.SetHeader("Subject", subject.String())
	message.SetBody("text/plain", plainBody.String())      //  设置plain-text body  纯文本正文
	message.AddAlternative("text/html", htmlBody.String()) //  设置html body 超文本语言正文

	//打开一个到SMTP服务器的链接,发送信息,关闭链接。如果超时,返回"dial tcp: i/o timeout"
	err = m.dialer.DialAndSend(message)
	if err != nil {
		return err
	}
	return nil

}

加载SMTP服务配置

使用命令行加载SMTP配置,这里的ip地址为本地地址localhost,端口号根据自己开启的fakeSMTP服务器端口号调整。

go 复制代码
flag.StringVar(&cfg.smtp.host, "smtp-host", "localhost", "SMTP host")
flag.IntVar(&cfg.smtp.port, "smtp-port", 25, "SMTP port")
//  服务器和密码用来登录smtp服务器的,这里用的本地的fakeSMTP服务器,所以填不填无所谓
flag.StringVar(&cfg.smtp.username, "smtp-username", "***", "SMTP username")
flag.StringVar(&cfg.smtp.password, "smtp-password", "***", "SMTP password")
flag.StringVar(&cfg.smtp.sender, "smtp-sender", "Greenlight <[email protected]>", "SMTP sender")

初始化mailer实例,将其加载到application配置中供handler使用

go 复制代码
app := &application{
		config: cfg,
		logger: logger,
		models: data.NewModels(db),
		mailer: mailer.New(cfg.smtp.host, cfg.smtp.port, cfg.smtp.username, cfg.smtp.password, cfg.smtp.sender),
	}

运行结果

Fake SMTP Server接收示例

具体的邮件内容

在邮件内的具体内容

相关推荐
DemonAvenger3 分钟前
深入剖析 sync.Once:实现原理、应用场景与实战经验
分布式·架构·go
一个热爱生活的普通人1 天前
Go语言中 Mutex 的实现原理
后端·go
孔令飞1 天前
关于 LLMOPS 的一些粗浅思考
人工智能·云原生·go
小戴同学1 天前
实时系统降低延时的利器
后端·性能优化·go
Golang菜鸟2 天前
golang中的组合多态
后端·go
Serverless社区2 天前
函数计算支持热门 MCP Server 一键部署
go
Wo3Shi4七2 天前
二叉树数组表示
数据结构·后端·go
网络研究院2 天前
您需要了解的有关 Go、Rust 和 Zig 的信息
开发语言·rust·go·功能·发展·zig
27669582922 天前
拼多多 anti-token unidbg 分析
java·python·go·拼多多·pdd·pxx·anti-token
程序员爱钓鱼3 天前
Go 语言邮件发送完全指南:轻松实现邮件通知功能
后端·go·排序算法