使用golang发送邮件

news/2024/12/22 13:58:13/

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

这里从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.ppmy.cn/news/1338666.html

相关文章

Cache Lab:Part A【模拟出使用LRU策略的高速缓存存储器组织结构】

目录 任务描述 知识回顾 实验内容 测试结果 Cache Lab 对应《CS:APP》6.3节至第六章结束的内容。 任务描述 Your job for Part A is to fill in the csim.c file so that it takes the same command line arguments and produces the identical output as the reference …

Django如何调用机器学习模型进行预测

Django是一个流行的Python Web框架,它可以很方便地集成机器学习模型,进行预测和推理。我将介绍如何在Django项目中调用训练好的机器学习模型,并实现一个预测接口。 准备工作 首先我们需要一个训练好的机器学习模型。这里我们使用Scikit-Learn训练一个简单的线性回归模型作为示…

鸿蒙会取代Android吗?听风就是雨

现在说取代还谈不上,毕竟这需要时间。安卓作为全球第一的手机操作系统,短时间内还无法取代。持平iOS甚至超过iOS有很大可能,最终会呈现“三足鼎立”有望超过安卓基数。 作为全新的鸿蒙操作系统,其现在已经是全栈自研底座。按照鸿…

2024Node.js零基础教程(小白友好型),nodejs新手到高手,(三)NodeJS入门——http协议

033_HTTP协议_初识HTTP协议 hello,大家好,这个小节我们来认识一下 http协议。 http是几个单词的首字母拼写,全称为Hypertext Transfer Protocol 译为超文本传输协议,那么这个http协议是互联网上应用最广泛的协议之一。顺便说一下…

苹果提审被拒反馈崩溃日志.text | iOS 审核被拒crashLog

iOS审核人员拒绝后每个截图,只给了几个text文件,这种情况就是审核的时候运行你的代码,崩溃了。 仅仅看text文件,是看不出所以然来的,所以我们要将日志转换成.crash格式 1.将.text文件下载下来,将 .text手动…

【每日一题】 2024年1月汇编

🔥博客主页: A_SHOWY🎥系列专栏:力扣刷题总结录 数据结构 云计算 数字图像处理 力扣每日一题_ 【1.4】2397.被列覆盖的最多行数 2397. 被列覆盖的最多行数https://leetcode.cn/problems/maximum-rows-covered-by-columns/ 这…

滇西科技师范学院食堂大宗物资采购项目(冰冻制品类)招标公告

滇西科技师范学院食堂大宗物资采购项目(冰冻制品类)招标公告 (招标编号:YDZOH20240158) 项目所在地区:云南省,临沧市,市辖区 一、招标条件 本滇西科技师范学院食堂大宗物资采购项目(冰冻制品类)已由项目审批/核准/备案机关批准,项目资金来源为…

C#网络爬虫之TianyaCrawler实战经验分享

互联网时代的到来带来了大量的数据,而网络爬虫技术成为了获取这些数据的重要途径之一。如果你是一名C#开发者,那么你可能会对TianyaCrawler这个强大的网络爬虫框架感兴趣。本文将带你深入了解TianyaCrawler,分享它的技术概况、使用场景&#…