Go:实现SMTP邮件发送订阅功能(包含163邮箱、163企业邮箱、谷歌gmail邮箱)
需求很简单,就是用户输入自己的邮箱后,使用官方邮箱给用户发送替邮件模版

目录
- 前置
- 邮件模版
- 邮箱开启SMTP服务
- 163邮箱
- 163企业邮箱
- 谷歌gmail邮箱
- 腾讯企业邮箱-失败
- 其他邮箱-未操作
- 邮件发送核心代码
- config.yaml配置
- 读取邮件相关配置
- 发送邮件
- 附录
前置
邮件模版
邮件模版类似如下图发来的欢迎加入的模版

这里我们使用html格式存储模版,上图源码如下
<html lang="en-US" xmlns:th="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>email</title><style>a{color: #ECC94B !important;}.foot-text{color: rgba(0, 0, 0, 0.50) !important;}.im{color:rgba(0,0,0,0.86) !important;}.center {display: flex;justify-content: center;align-items: center;}</style>
</head>
<body style="background-color: white;">
<div style="width: 640px;height: auto;border-radius: 5px;margin: 0 auto;position: relative; padding-bottom: 80px; padding-top: 20px"><div><img width="640" src="file:///Users/yanzhixing/Downloads/My/文档/HatchfulExport-All/linkedin_banner_image_2.png" alt=""></div><div style="color: rgba(0,0,0,0.86);font-family: 'Roboto','Century Gothic', 'Trebuchet MS', 'Hiragino Sans GB', 微软雅黑, 'Microsoft Yahei', Tahoma, Helvetica, Arial, 'SimSun', sans-serif;font-size: 16px;margin: 10px auto 0px"><h2 style="font-size: 20px;font-weight: 700; color: #000">Dear KunZhi Fans,</h2><div><p style="margin: 16px 0; ">Welcome to the family! We are glad to have you on board as a subscriber to my blog.</p ><p style="font-weight: 600; color: #000;">Get the latest on <a style="color: #000" href="https://kunzhi.blog.csdn.net/">CSDN</a> and give me a follow if you haven't already.</p><p style="margin: 16px 0"><p style="font-weight: 600; color: #000">🧑🏻 About Me</p><p style="margin-bottom: 8px">Former Alibaba programmer, now working for a blockchain company. He is a blogger in the domestic Internet circle, an expert blogger on Alibaba Cloud, and the manager of CSDN Hangzhou City Community. Welcome to communicate and win-win cooperation.</p></p ><div style="margin: 16px 0"><p style="font-weight: 600; color: #000;">📇 Contact Me</p><p style=" margin-bottom: 8px">Should you have any questions, require assistance, or want to dive deeper into any aspect, you can reach out to me through various channels:</p><div><p style="margin-bottom: 0; display: flex; margin-bottom: 4px"><span style="margin: 0 8px">●</span><span>Wechat: Follow me <a style="color: #ECC94B;text-decoration: none " target="_blank">kunzhi96</a> to communicate and learn together.</span><div class="center"><img width="200" src="file:///Users/yanzhixing/Downloads/My/私人/微信二维码.png" alt=""></div></p><p style="margin: 0; display: flex; margin-bottom: 4px"><span style="margin: 0 8px">●</span><span>CSDN Blog: Visit my blog -<a style="color: #ECC94B; text-decoration: none" target="_blank" href="https://kunzhi.blog.csdn.net/">鲲志说</a> for in-depth information about my learning content and technology sharing.</span></p><p style="margin: 0; display: flex; margin-bottom: 4px"><span style="margin: 0 8px">●</span><span> Email: Feel free to contact us via email at <span style="color: #ECC94B; opacity: 1;">XXX@163.com</span> for any inquiries, feedback, or support needs.</span></p></div><p style="margin-bottom: 0px">I'm excited to embark on this journey with you.</p></div ><p>Warm regards,</p><p>Kun Zhi</p><div style="background-color: #F7F7F7; padding: 40px; text-align:center;"><p style="font-size: 24px;font-weight: 700; color: #000; margin-bottom: 24px; margin-top: 0">KunZhi</p><p style="margin-bottom: 8px; margin-top: 0">This email was send to <span style="color: #ECC94B; opacity: 1;">xxx@gmail.com</span></p><p style="margin-bottom: 24px; margin-top: 0">You’ve received it because you’ve subscribed to our newsletter.</p><div><a style="color: rgba(0, 0, 0, 0.50); text-decoration: underline" href="unsubscribe_url/unsubscribe?email=unsubscribe_email" class="foot-text">Unsubscribe</a></div></div></div></div>
</div>
</body>
</html>
邮箱开启SMTP服务
选择好官方邮箱来开启smtp服务,这里我测试验证了163邮箱、163企业邮箱、谷歌gmail邮箱和腾讯企业邮箱(但腾讯企业邮箱未成功,后续会说明)
163邮箱
-
登录163邮箱(一定不要登录到简易版啊)
-
登录后如下图所示,点击上面导航栏的设置

-
按照下图顺序点击 POP3/SMTP/IMAP

-
开启SMTP服务
如下图我已经是开启状态了

5. 新增授权密码
如上图,我们如果需要使用SMTP服务,就一定要使用授权码,而且这个密码只出现一次,一定要记得保存好,保存好先留着,我们后面会用到
6.服务器地址及端口
我们使用的是SMTP服务,则对应的服务器地址是smtp.163.com,端口为25,后面都会用到

自此,163邮箱的smtp服务开启完毕,可直接跳到邮件发送源码处继续即可
163企业邮箱
- 登录163企业邮箱
可以看到登录的是网易灵犀办公界面

- 登录后如下图所示,点击上面导航栏的设置-账号与安全-客户端设置

- 进入客户端设置
可看到如下图
- 选择IMAP协议
- 开启并设置客户端授权密码

- 新增授权密码
如上图,生成授权码,而且这个密码只出现一次,一定要记得保存好,保存好先留着,我们后面会用到。
可以看到163企业邮箱不同的是,有一个到期时间,也就意味着,到期了,我们需要更换授权码,这一点需要谨记
- 服务器地址及端口
我们使用的是SMTP服务,则对应的服务器地址是smtphz.qiye.163.com,端口为25,后面都会用到

自此,163企业邮箱的smtp服务开启完毕,可直接跳到邮件发送源码处继续即可
谷歌gmail邮箱
- 登录 谷歌gmail邮箱
- 点击设置-查看所有设置

- 点击转发和 POP/IMAP 标签页,如下图进行启用设置,并保存更改

- 创建和使用应用专用密码
-
前往您的 Google 帐号-选择安全性
-
在“登录 Google”下方,选择两步验证

-
在页面底部,选择应用专用密码,进行点击

-
输入一个名称,以帮助您记住在什么情况下使用应用专用密码,如我的kunzhi-test

-
选择创建后,会出现如下弹窗。设备的应用专用密码即生成了,是指在设备上生成的 16 个字符的代码。也就是授权码,而且这个密码只出现一次,一定要记得保存好,保存好先留着,我们后面会用到。

-
选择完成,记得应用名称对应的密码即可

- 服务器地址及端口
我们使用的是SMTP服务,则对应的服务器地址是smtp.gmail.com,端口为587,后面都会用到

自此,谷歌gmail邮箱的smtp服务开启完毕,可直接跳到邮件发送源码处继续即可
腾讯企业邮箱-失败
腾讯企业邮箱失败的原因是因为一直没有找到授权码在哪里进行设置,同时使用邮箱的密码作为授权码也无法发送邮件,所以一直没有实现,但是前面的操作步骤可以放出来供大家参考,如果有人找到了腾讯企业邮箱的操作方法请一定要评论区给出解法。
-
企业微信管理后台
-
开启腾讯企业邮箱的POP/SMTP/IMAP服务

-
企业邮箱服务器及端口号设置
其他邮箱-未操作
这个链接的操作我并未实际执行,需要的可以参考
- 发件服务设置-包含:阿里云邮箱设置、Outlook邮箱设置
邮件发送核心代码
config.yaml配置
这里是发送邮件的邮箱相关配置,这里就使用到之前只出现一次的授权码了,以及对应的服务器地址和端口
email:
# 163邮箱template_dir: /test.htmlsmtp_server: smtp.163.comsmtp_port: 25smtp_user: KunZhismtp_password: 授权码from_email: XXXX@163.com# 腾讯企业邮箱# smtp_server: smtp.exmail.qq.com# smtp_port: 465# smtp_user: KunZhi# smtp_password: 授权码# from_email: XXXX# 163企业邮箱# smtp_server: smtphz.qiye.163.com# smtp_port: 25# smtp_user: KunZhi# smtp_password: 授权码# from_email: XXXX# gmail
# smtp_server: smtp.gmail.com
# smtp_port: 587
# smtp_user: KunZhi
# smtp_password: 授权码
# from_email: XXXX@gmail.com
这里的smtp_user如下图,就是展示的发件人名称

读取邮件相关配置
//读取邮件相关配置err = sendWelcomeEmail(Cfg{SenderAddress: viper.GetString("email.from_email"),SenderName: viper.GetString("email.smtp_user"),SenderPwd: viper.GetString("email.smtp_password"),MailServerHost: viper.GetString("email.smtp_server"),MailServerPort: viper.GetString("email.smtp_port"),}, viper.GetString("email.from_email"), toEmail, unsubscribeUrl)if err != nil {errors.Errorf("Failed to send email: ", toEmail, err)responseData := gin.H{"message": "Failed to send email: " + toEmail,"code": -1,}c.JSON(http.StatusOK, responseData)return err}
发送邮件
func sendWelcomeEmail(cfg Cfg, template string, recipientEmail, unsubscribeUrl string) error {currentDir, err2 := os.Getwd()if err2 != nil {log.Fatalf("Failed to get current working directory: %v", err2)}//获取邮件模版htmlContent, err3 := ioutil.ReadFile(currentDir + viper.GetString("email.template_dir"))if err3 != nil {fmt.Println("Failed to read HTML file:", err3)return err3}// 邮件标题subject := "Your Journey Begins Here"message := string(htmlContent)// 需要替换邮件模版中的字符串映射replacements := map[string]string{"xxx@gmail.com": recipientEmail,"header_img": viper.GetString("img.header_img"),}// 替换字符串for oldStr, newStr := range replacements {message = strings.Replace(message, oldStr, newStr, -1) // -1 表示替换所有匹配项}// 连接到 SMTP 服务器并发送电子邮件auth := smtp.PlainAuth("", cfg.SenderAddress, cfg.SenderPwd, cfg.MailServerHost)to := []string{recipientEmail}msg := []byte("To: " + recipientEmail + "\r\n" +"Subject: " + subject + "\r\n" +"From: " + cfg.SenderName + " <" + cfg.SenderAddress + ">\r\n" +"MIME-Version: 1.0\r\n" +"Content-Type: text/html; charset=utf-8\r\n" + // 将内容类型设置为 HTML"\r\n" + message)//发送邮件err := smtp.SendMail(cfg.MailServerHost+":"+cfg.MailServerPort, auth, cfg.SenderAddress, to, msg)if err != nil {fmt.Println("failed to send email:", err)return err}return nil
}
如上代码,可以实现SMTP邮件发送订阅功能,如有任何问题欢迎私聊或评论区留言
附录
- 163帮助中心
- 163邮箱无法发送邮件发生退信问题 550 User has no permission以及554, DT:SPM的解决办法
- 163企业邮箱帮助中心-灵犀办公客户端的设置方法
- 谷歌邮箱-使用应用专用密码登录
相关文章:
Go:实现SMTP邮件发送订阅功能(包含163邮箱、163企业邮箱、谷歌gmail邮箱)
需求很简单,就是用户输入自己的邮箱后,使用官方邮箱给用户发送替邮件模版 目录 前置邮件模版邮箱开启SMTP服务163邮箱163企业邮箱谷歌gmail邮箱腾讯企业邮箱-失败其他邮箱-未操作 邮件发送核心代码config.yaml配置读取邮件相关配置发送邮件 附录 前置 邮…...
Scala第十六章节
Scala第十六章节 scala总目录 文档资料下载 章节目标 掌握泛型方法, 类, 特质的用法了解泛型上下界相关内容了解协变, 逆变, 非变的用法掌握列表去重排序案例 1. 泛型 泛型的意思是泛指某种具体的数据类型, 在Scala中, 泛型用[数据类型]表示. 在实际开发中, 泛型一般是结合…...
C语言 实现 链 显示 效果 查找 修改 删除
显示所有信息 2023年10月1日的描述:今天放假 2023年10月2日的描述:今天有体育 2023年10月3日的描述:今天有数学 2023年10月4日的描述:今天有语文 2023年10月5日的描述:今天有政治 2023年10月6日的描述:今天交学费 2023年10月7日的描述:今天周末 2023年10月8日的描述:今天给家里…...
CSS基础语法第一天
目录 一、CSS 简介 1.1 CSS简介 1.2 CSS语法 1.3 CSS 语法规范 1.4 CSS 代码风格 1.4.1 样式格式书写 1.4.2 样式大小写 1.4.3 空格规范 二、CSS 基础选择器 2.1选择器分类 2.2标签选择器 2.3 类选择器 2.4 id选择器 2.5 通配符选择器 三、盒子尺寸和背景色 …...
Leetcode 1492.n的第k个因子
给你两个正整数 n 和 k 。 如果正整数 i 满足 n % i 0 ,那么我们就说正整数 i 是整数 n 的因子。 考虑整数 n 的所有因子,将它们 升序排列 。请你返回第 k 个因子。如果 n 的因子数少于 k ,请你返回 -1 。 示例 1: 输入&#…...
十一工具箱流量主小程序源码
无授权,去过滤机制版本 看到网上发布的都是要授权的 朋友叫我把他去授权,能用就行 就把过滤去了 这样就不用授权 可以免费使用 白嫖党专属 一切接口可用,无需担心不能用 授权者不关站一直可以用 源码下载:https://download.csdn.…...
10.5汇编语言整理
【汇编语言相关语法】 1.汇编语言的组成部分 1.伪操作:不参与程序的执行,但是用于告诉编译器程序该怎么编译 .text .global .end .if .else .endif .data 2.汇编指令 编译器将一条汇编指令编译成一条机器码,在内存里一条指令占4字节内存&…...
Connect to 127.0.0.1:1080 [/127.0.0.1] failed: Connection refused: connect
报错信息 A problem occurred configuring root project CourseSelection. > Could not resolve all artifacts for configuration :classpath.> Could not resolve com.android.tools.build:gradle:3.6.1.Required by:project :> Could not resolve com.android.tool…...
驱动器类产品的接口EMC拓扑方案
驱动器类产品的接口EMC拓扑方案 1. 概述 本文以高压伺服驱动器和变频器类产品为例,对常用端口滤波拓扑方案进行总结,后续根据不同的应用场景可进行适当删减,希望对大家有帮助。 2. 驱动器验证等级 本文推荐拓扑的实验结果,满足…...
2023最新ICP备案查询系统源码 附教程 Thinkphp框架
2023最新ICP备案查询系统源码 附教程 thinkphp框架 本系统支持网址备案,小程序备案,APP备案查询,快应用备案查询 优势: 响应速度快,没有延迟,没有缓存,数据与官方同步 源码下载:ht…...
大数据Doris(六):编译 Doris遇到的问题
文章目录 编译 Doris遇到的问题 一、js_generator.cc:(.text+0xfc3c): undefined reference to `well_known_types_js’...
vue重修004上部
文章目录 版权声明组件的三大组成部分scoped解决样式冲突scoped原理2.代码演示 组件data函数说明演示 组件通信组件关系分类通信解决方案父子通信流程子向父通信代 props详解props校验props&data、单向数据流 小黑记事本(组件版)基础组件结构需求和实…...
【C++ techniques】要求/禁止/判断—对象产生于堆中
有时候我们想让某种对象具有“自杀”的能力,所以我们必须要求对象存在堆中,以便我们调用delete this;另一些时候,我们要求拥有某种确定性,保证某一些类型绝不会发生内存泄漏,原因是没有任何一个该类型的对象…...
吃鸡高手亲授:玩转绝地求生,分享顶级游戏干货!
绝地求生(PUBG)自上线以来,成为了全球热门游戏。作为吃鸡行家,我将分享一些独家技巧和干货,帮助您提高游戏战斗力,享受顶级游戏作战体验! 首先,让我们谈一谈战斗力升级。想要在吃鸡游…...
Vue中如何进行自定义图表与可视化图形设计
Vue中如何进行自定义图表与可视化图形设计 在现代Web应用程序开发中,数据可视化图表和图形设计是至关重要的一部分。Vue.js是一个流行的JavaScript框架,它提供了强大的工具来构建交互性强大的用户界面。本文将探讨如何在Vue.js中进行自定义图表和可视化…...
学信息系统项目管理师第4版系列19_质量管理
1. 公差 1.1. 质量测量中公差是测量指标的可允许变动范围,而不是实际测量值与预期值的差 1.1.1. 【高22下选35】 1.2. 结果的的可接受范围 2. 控制界限 2.1. 统计意义上稳定的过程或过程绩效的普通偏差的边界 3. 3版 3.1. 质量控制新七工具 3.1.1. 【高19下…...
react库的基础学习
React介绍 React.js是前端三大新框架:Angular.js、React.js、Vue.js之一,这三大新框架的很多理念是相同的,但是也有各自的特点。 React起源于Facebook的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满…...
FFmpeg 基础模块:容器相关的 API 操作
目录 AVFormat 模块 AVFormat 前处理部分 AVFormat 读写处理部分 小结 思考 FFmpeg 目录中包含了 FFmpeg 库代码目录、构建工程目录、自测子系统目录等,具体内容如下: 现在你知道 FFmpeg 的源代码目录中都包含了哪些内容,在之后使用 FFm…...
SpringMVC+统一表现层返回值+异常处理器
一、统一表现层返回值 根据我们不同的处理方法,返回的数据格式都会不同,例如添加只返回true|false,删除同理,而查询却返回数据。 Result类 为此我们封装一个result类来用于表现层的返回。 public class Result {//描述统一格式…...
2023年地理信息系统与遥感专业就业前景与升学高校排名选择
活动地址:毕业季进击的技术er 地理信息系统(GIS,Geographic Information System),又称“地理信息科学”(Geographic Information Science),是一种具有信息系统空间专业形式的数据管理…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
【JavaSE】多线程基础学习笔记
多线程基础 -线程相关概念 程序(Program) 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为该进程分配内存…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能
1. 开发环境准备 安装DevEco Studio 3.1: 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK 项目配置: // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...
HubSpot推出与ChatGPT的深度集成引发兴奋与担忧
上周三,HubSpot宣布已构建与ChatGPT的深度集成,这一消息在HubSpot用户和营销技术观察者中引发了极大的兴奋,但同时也存在一些关于数据安全的担忧。 许多网络声音声称,这对SaaS应用程序和人工智能而言是一场范式转变。 但向任何技…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
【LeetCode】算法详解#6 ---除自身以外数组的乘积
1.题目介绍 给定一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O…...
