使用golang发送邮件

目前大多应用都是手机登录,但是作为开源的一个软件,或者是私有的一个应用,那么使用手机短信接收验证码成本比较高,使用邮箱相对更容易,

这里从tinode中取出发邮件的部分做一个测试,

其中邮箱一般需要设置后才能使用SMTP方式发送邮件,设置方式参考:

使用tinode架设自己的私有聊天服务

邮件其实是有格式的,不是随便发一个字符串过去就好了

func randomBoundary() string {var buf [24]byterand.Read(buf[:])return fmt.Sprintf("tinode--%x", buf[:])
}func GetMessage(SendFrom, to, title, dataType, content string) ([]byte, error) {message := &bytes.Buffer{}// Common headers.fmt.Fprintf(message, "From: %s\r\n", SendFrom)fmt.Fprintf(message, "To: %s\r\n", to)message.WriteString("Subject: ")// Old email clients may barf on UTF-8 strings.// Encode as quoted printable with 75-char strings separated by spaces, split by spaces, reassemble.message.WriteString(strings.Join(strings.Split(mime.QEncoding.Encode("utf-8", title), " "), "\r\n    "))message.WriteString("\r\n")message.WriteString("MIME-version: 1.0;\r\n")if dataType == "plain" {// Plain text messagemessage.WriteString("Content-Type: text/plain; charset=\"UTF-8\"; format=flowed; delsp=yes\r\n")message.WriteString("Content-Transfer-Encoding: base64\r\n\r\n")b64w := base64.NewEncoder(base64.StdEncoding, message)b64w.Write([]byte(content))b64w.Close()} else if dataType == "html" {// HTML-formatted messagemessage.WriteString("Content-Type: text/html; charset=\"UTF-8\"\r\n")message.WriteString("Content-Transfer-Encoding: quoted-printable\r\n\r\n")qpw := qp.NewWriter(message)qpw.Write([]byte(content))qpw.Close()} else {// Multipart-alternative message includes both HTML and plain text components.boundary := randomBoundary()message.WriteString("Content-Type: multipart/alternative; boundary=\"" + boundary + "\"\r\n\r\n")message.WriteString("--" + boundary + "\r\n")message.WriteString("Content-Type: text/plain; charset=\"UTF-8\"; format=flowed; delsp=yes\r\n")message.WriteString("Content-Transfer-Encoding: base64\r\n\r\n")b64w := base64.NewEncoder(base64.StdEncoding, message)b64w.Write([]byte(content))b64w.Close()message.WriteString("\r\n")message.WriteString("--" + boundary + "\r\n")message.WriteString("Content-Type: text/html; charset=\"UTF-8\"\r\n")message.WriteString("Content-Transfer-Encoding: quoted-printable\r\n\r\n")qpw := qp.NewWriter(message)qpw.Write([]byte(content))qpw.Close()message.WriteString("\r\n--" + boundary + "--")}message.WriteString("\r\n")return message.Bytes(), nil
}

这里使用了用户名密码验证:

SMTP(Simple Mail Transfer Protocol)支持多种认证方式,其中常见的包括:

  1. PLAIN: 客户端将用户名和密码以明文形式发送给服务器进行认证。这是一种最简单的认证方式,但是由于信息以明文形式传输,安全性较低。

  2. LOGIN: 客户端发送用户名和密码,但是这次发送的是经过 BASE64 编码的形式。尽管没有以明文形式传输,但仍然不够安全,因为 BASE64 编码可以容易地解码。

  3. CRAM-MD5: 客户端和服务器之间进行挑战-响应式的认证。服务器发送一个挑战给客户端,客户端使用密码进行哈希处理后的响应进行回复。这种方式更加安全,因为密码不会以明文形式传输。


import ("bytes""crypto/tls""encoding/base64""fmt""math/rand""mime"qp "mime/quotedprintable""net/smtp""strings"
)type Validator struct {SMTPAddr              stringSMTPPort              stringSMTPHeloHost          stringTLSInsecureSkipVerify boolauth                  smtp.Auth
}type loginAuth struct {username, password []byte
}func (a *loginAuth) Start(server *smtp.ServerInfo) (string, []byte, error) {return "LOGIN", []byte(a.username), nil
}// Next continues the authentication. Exported only to satisfy the interface definition.
func (a *loginAuth) Next(fromServer []byte, more bool) ([]byte, error) {if more {switch strings.ToLower(string(fromServer)) {case "username:":return a.username, nilcase "password:":return a.password, nildefault:return nil, fmt.Errorf("LOGIN AUTH unknown server response '%s'", string(fromServer))}}return nil, nil
}

发送一个邮件:


var user string = "test1@sina.com"
var touser string = "test1@qq.com"
var pass string = "1234566"func TestMail() {auth := &loginAuth{[]byte(user), []byte(pass)}v := Validator{"smtp.sina.com","25","sina.com",false,auth,}msg, _ := GetMessage(user, touser, "it is a test.", "plain", "这是一个测试")err := v.SendMail([]string{touser}, msg)fmt.Println(err)
}func (v *Validator) SendMail(rcpt []string, msg []byte) error {client, err := smtp.Dial(v.SMTPAddr + ":" + v.SMTPPort)if err != nil {return err}defer client.Close()if err = client.Hello(v.SMTPHeloHost); err != nil {return err}if istls, _ := client.Extension("STARTTLS"); istls {tlsConfig := &tls.Config{InsecureSkipVerify: v.TLSInsecureSkipVerify,ServerName:         v.SMTPAddr,}if err = client.StartTLS(tlsConfig); err != nil {return err}}if v.auth != nil {if isauth, _ := client.Extension("AUTH"); isauth {err = client.Auth(v.auth)if err != nil {fmt.Println(err)return err}}}if err = client.Mail(user); err != nil {fmt.Println(err)return err}for _, to := range rcpt {if err = client.Rcpt(strings.ReplaceAll(strings.ReplaceAll(to, "\r", " "), "\n", " ")); err != nil {return err}}w, err := client.Data()if err != nil {return err}if _, err = w.Write(msg); err != nil {return err}if err = w.Close(); err != nil {return err}return client.Quit()
}

如果不报错,就去收件箱接收邮件就好了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/657734.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity异步加载场景

前言 Unity中常见的加载场景就是异步加载场景,此博客对异步加载场景进行详细介绍 简单易懂好用。含有加载进度,加载动画等。(文末附工程) 代码分析 主要脚本MaskPanel ,作为单例存在于场景中,下面对此脚…

Angular组件(二) 分割面板ShrinkSplitter

Angular组件(二) 分割面板ShrinkSplitter 前言 在Angular组件(一) 分割面板ShrinkSplitter文章中我们实现了Splitter组件,后来在业务场景中发现在开关右侧容器和底部容器时,使用起来不方便,ngModel绑定的值始终是左侧容器和顶部容器的大小&…

Flutter App 生命周期观察监听

前言 本文主要讲解两种 Flutter生命周期观察监听 方式一:Flutter SDK 3.13 之前的方式,WidgetsBindingObserver; 方式二:Flutter SDK 3.13 开始的新方式,AppLifecycleListener; 测试平台:IO…

走进水稻种植教学基地可视化:科技与农业知识的完美结合

随着科技的不断发展,农业领域也在不断创新和进步。水稻种植教学基地可视化系统是一种基于现代信息技术手段的教学方式,通过虚拟现实、3D建模等技术,将水稻种植的全过程进行模拟和展示。这种教学方式打破了传统农业教学的局限性,使…

idea中yml文件没有提示解决办法

两步解决yml文件不显示提示,yaml文件显示提示问题 1、在插件中心,先下载下图两个插件 2、在Editor》File Types新增文件类型,文件名匹配规则需要将yaml和yml的都加上,加好之后,重启idea,即刻生效。

专利背后的故事 | 一种基于FTP文件的下载方法

Part 01 专利发明的初衷 FTP下载工具俗称为FTP工具,是我们常用的一个服务。FTP分为客户端和服务器端:FTP服务器被用于存储文件;FTP客户端用于通过FTP协议访问位于FTP服务器端上的资源,可以上传和下载文件。 在现实使用中可能会…

C++进阶--继承

概念 继承,允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承属性和方法。 继承的主要目的是实现代码的重用和构建类之间的层次关系。通过继承,子类可以获得父类的特性,包括数据成员…

嵌合抗体介绍-泰克生物

一.嵌合抗体简介 人-鼠嵌合抗体,即抗体的可变区来自鼠单克隆抗体,而恒定区则来自人的抗体。它是通过从杂交瘤细胞分离出功能性可变区基因,与人Ig恒定区基因连接,插入适当表达载体,转染宿主细胞表达产生。嵌合抗体既保留…

centOS+nodejs+mysql阿里云部署前后端个人网站

centOSnodejsmysql阿里云部署前后端个人网站 参考: 部署NodeExpressMySQL项目到阿里云轻量应用服务器 阿里云轻量应用服务器部署Node.jsReactMongoDB前后端分离项目 参考:在阿里云上部署nodejs服务 https 部署的原理就是你在本地测试的时候在地址栏&am…

给零基础朋友的编程课12 代码

给零基础朋友的编程课12 下 - 仿制品7 案例_哔哩哔哩_bilibili 源代码: // 色表 // 桃红 254,181,167 // 粉红 255,208,199void setup() {size(1000,750);background(254,181,167); }void draw() {// 绘制画框stroke(255,208,199);strokeWeight(28);noFill();rect…

Cmake编译Opencv3.3.1遇到有些文件无法下载的错误解决:

前言: 对于,opencv有些配置文件错误并未致命,所以,有错误也不影响后续的编译:但是,后引用如果要用,在回过头来还是要解决的。 问题表述: 比如,有些文件下载的错误&am…

Linux可视化管理

记得看目录哦! 1. webmin2. webmin安装及配置2.1 把软件传到opt目录下的webmin目录2.2 解压rpm -ivh webmin-1.700-1.noarch.rpm2.3 重置webmin的root密码2.4 修改webmin的端口2.5 重启webmin2.6 放开6666端口的防火墙2.7 网址输入ip:端口号 3. webmin的…

自建DNS劫持服务器,纯内网劫持PS5,屏蔽更新,自动hen

背景:目前PS5首次折腾必须要连外网,还要改DNS,除非使用ESP8266/32, 本文的方法是完全不改DNS,不使用ESP8266,不连接外网的情况下自动折腾 能实现什么: 1.折腾全程不连接外网 2.完全自建hen服务器&#xff…

维护管理Harbor,docker容器的重启策略

维护管理Harbor 通过HarborWeb创建项目 在 Harbor 仓库中,任何镜像在被 push 到 regsitry 之前都必须有一个自己所属的项目。 单击“项目”,填写项目名称,项目级别若设置为"私有",则不勾选。如果设置为公共仓库&#…

[C++]类和对象(上)

目录 一:面向过程与面向对象的区别 二:类的定义 三:类的访问限定符和封装 3.1访问限定符 3.2 封装 四:类的实例化 五:类对象模型 如何计算类的大小 类对象的存储方式 六:this指针 this指针的引出 this指针的特性 一:面向过程与面向对象的区别 面向过程 C语言是面…

[机器学习]TF-IDF算法

一.TF-IDF算法概述 什么是TF-IDF? 词频-逆文档频率(Term Frequency-Inverse Document Frequency,TF-IDF)是一种常用于文本处理的统计方法,可以评估一个单词在一份文档中的重要程度。简单来说就是可以用于文档关键词的提…

SQL注入:宽字节注入

SQL注入系列文章: 初识SQL注入-CSDN博客 SQL注入:联合查询的三个绕过技巧-CSDN博客 SQL注入:报错注入-CSDN博客 SQL注入:盲注-CSDN博客 SQL注入:二次注入-CSDN博客 ​SQL注入:order by注入-CSDN博客 …

wordcloud库和jieba库的使用

文章目录 wordcloud库的简单示范使用wordcloud库报错记录anaconda安装第三方jieba库jieba库的简单示范任务 1:三国演义中的常见词汇分布在“三国"这两个隶书字上,出现频率高的词字体大任务 2:三国演义中出现频率前十的人名。必须是以下这…

python爬虫学习之selenium_chrome handless的使用

目录 一、Chrome handless简介 二、Chrome handless的系统要求 三、Chrome handless的基本配置 (直接复制放在.py文件开头) 四、Chrome handless 的应用 五、Chrome handless的封装 一、Chrome handless简介 Chrome handless 模式,Goog…

JZ15 二进制中1的个数(牛客)(C语言)

个人博客主页:https://blog.csdn.net/2301_79293429?typeblog 专栏:https://blog.csdn.net/2301_79293429/category_12545690.html 该题我为笨办法,与题解不同,如有疑问和见解,欢迎大家在评论区提出 题目链接: 二进制中1的个数_牛客题霸_牛客网 (now…