当前位置: 首页 > article >正文

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

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

编辑邮件模版

主要包含三个template:

  1. subject:主题
  2. plainBody: 纯文本正文
  3. htmlBody:超文本语言正文
{{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中,最后打包信息发送

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 <alice@example.com>"
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服务器端口号调整。

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 <no-reply@greenlight.alexedwards.net>", "SMTP sender")

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

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接收示例
在这里插入图片描述
具体的邮件内容
在这里插入图片描述
在邮件内的具体内容
在这里插入图片描述


http://www.kler.cn/a/447648.html

相关文章:

  • OpenResty、Lua介绍认识
  • Restaurants WebAPI(三)——Serilog/
  • lambda初探(一)
  • 为何VisualRules更适合技术人员使用
  • springboot 配置Kafka 关闭自启动连接
  • 火山引擎发布数据飞轮 2.0,AI 重塑企业数据消费
  • 【学习总结|DAY022】Java网络编程
  • 学习笔记:Verilog过程结构及在线仿真
  • MFC 实现动态控件调整和主题切换
  • 驾驶证识别API-JavaScript驾驶证ocr接口集成-场景解析
  • xcode15 报错 does not contain ‘libarclite‘
  • 2-Gin 框架中的路由 --[Gin 框架入门精讲与实战案例]
  • SpringBoot集成Canal实现MySQL实时同步数据到Redis
  • android anr 处理
  • Net9解决Spire.Pdf替换文字后,文件格式乱掉解决方法
  • Git(11)之log显示支持中文
  • 13_HTML5 Audio(音频) --[HTML5 API 学习之旅]
  • 使用R语言高效去除低丰度OTU:从概念到实操
  • Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印
  • 【LuaFramework】服务器模块相关知识
  • 基于BigBangBigCrunch优化(BBBC)的目标函数求解算法matlab仿真
  • 【Rust自学】5.1. 定义并实例化struct
  • AtCoder Beginner Contest 385(A~E)题解
  • OpenEuler22.04配置zookeeper+kafka三节点集群
  • 前端滚动条自定义样式
  • 渗透测试-前后端加密分析之RSA+AES