go发送smtp邮件时的踩坑记录——authlogin、
go发送smtp邮件时的踩坑记录——authlogin、x509:
cannotvalida。。。
最近在⽤go写⼀个⼩⼯具,⼀个⼩功能是⽤smtp发邮件,⽤公司内⽹的邮箱服务器实现踩了不少坑
想知道x509: cannot validate certificate for解决的直接看2.2.1,想知道auth login怎么实现看2.2.2
1 smtp协议
基础知识,回顾⼀下smtp协议的基本使⽤
1.1 命令⾏通过smtp协议发邮件
smtp协议⽹上资料很多,这⾥⽤最简单的⽅法过⼀遍,⽤的是qq邮箱
qq邮箱在使⽤smtp协议的时候,⽤的不是qq密码,⽽是⼀个叫授权码的东西,我们去qq邮箱设置——账户⾥到⽣成授权码
他会让你⽤密保⼿机发短信到某个号码,照做即可获得⼀个16位字母的授权码,保存好
去⼀个在线加密base64的⽹站,我⽤的是这个
把⽤来发邮件的qq邮箱账号和授权码转成base64编码
现在打开命令⾏,连接qq的smtp服务器和端⼝,qq的是smtp.qq:25
telnet smtp.qq 25
要和他打个招呼,后⾯跟着的不⼀定要是smtp,我不是很清楚这个有什么区别,我试着是什么都⾏
helo smtp
接下来就是验证你的⾝份,我们实验auth login法
auth login
分两⾏,填⼊刚才转换成base64的账号和授权码,这⾥也可以把账号和auth login放在⼀⾏写,下⼀⾏再写密码
响应235 Authentication successful,表⽰登陆成功
现在开始配置好发件⼈和收件⼈
mail from:<;你的发件邮箱>
rcpt to:<;接收邮箱>
输⼊data,开始写邮件内容,写完后⼀个.表⽰邮件结束,返回250 Ok: queued as,邮件就发出去了
data
subject:填写邮件主题
<;空⼀⾏>
填写邮件内容
...
邮件内容
.
1.2 smtp auth⽅式
之前⽤的是auth login⽅式,smtp还有很多其他⽅式,可参考这篇⽂章
⽤ehlo来代替helo命令,就可以查询这个邮件服务器⽀持的auth⽅式
我在qq邮箱和我公司邮件服务器上尝试ehlo,得到的返回如下
所以qq⽀持auth login和plain两种⽅式,我公司的邮件服务器只⽀持auth login,plain的格式是<NULL>账号<NULL>密码
2 如何⽤go发出⼀封auth login的邮件
春节短信大全2.1 官⽅是怎么说的
官⽅godoc给出了⼀个plain验证⽅式的发邮件代码
package main
import (
"log"
"net/smtp"
)
func main() {
// Set up authentication information.
auth := smtp.PlainAuth("", "user@example", "password", "ample")
// Connect to the server, authenticate, set the sender and recipient,
// and send the email all in one step.
to := []string{"recipient@example"}
msg := []byte("To: recipient@example\r\n" +
"Subject: discount Gophers!\r\n" +
"\r\n" +
"This is the email body.\r\n")
err := smtp.SendMail("ample:25", auth, "", to, msg)
if err != nil {
log.Fatal(err)
}
}
把上⾯的收发件⼈邮箱改好,邮箱服务器的hostname、端⼝改好,我⽤的qq邮箱,如果你⽤别的邮箱,smtp的端⼝号也查⼀下,不⼀定是25
密码记得要写授权码
运⾏之后邮件就发出去了
看⼀下内部代码,smtp包⾥这个SendMail函数,注释是我⾃⼰写的,⼤部分和之前telnet⾛的流程⼀致
/*
addr: 邮件 smtp 服务器地址
a:  验证对象
from: 发件箱
to:  收件⼈邮箱列表
msg: 发送的邮件信息
*/
func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
// 检测收发件邮箱地址是否有回车和换⾏
if err := validateLine(from); err != nil {
return err
}
for _, recp := range to {
if err := validateLine(recp); err != nil {
return err
}
}
// 和邮箱服务器建⽴ tcp 连接
c, err := Dial(addr)
if err != nil {
return err
}
defer c.Close()
// 发送helo信息
if err = c.hello(); err != nil {
return err
}
// 如果邮箱服务器⽀持 ssl/tls 加密
if ok, _ := c.Extension("STARTTLS"); ok {
config := &tls.Config{ServerName: c.serverName}  // tls 配置
// 测试安全连接
if testHookStartTLS != nil {
testHookStartTLS(config)
}
// 开始 tls 连接
if err = c.StartTLS(config); err != nil {
return err
}
}
// 验证
if a != nil && c.ext != nil {
// 若邮箱服务器不⽀持 auth,报错
if _, ok := c.ext["AUTH"]; !ok {
return errors.New("smtp: server doesn't support AUTH")
}
// 验证
if err = c.Auth(a); err != nil {
return err
}
}
// 填写发件邮箱
if err = c.Mail(from); err != nil {
return err
}
/
教师节的意义/ 填写收件邮箱
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
return err
}
}
// 邮件正⽂
w, err := c.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
}
return c.Quit()
}
2.2 然⽽换成我们公司的邮箱服务器就报错
2.2.1 证书错误
换上我们公司的邮箱服务器,报错
x509: cannot validate certificate for 10.141.72.4 because it doesn't contain any IP SANs
⽅法就是要修改代码,配置tls连接为跳过证书验证,我直接把smtp包复制了⼀份,命名为mySmtp/smtp,进⾏修改,修改注释的那⼀⾏就可以,增加InsecureSkipVerify为true的tls配置
func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
if err := validateLine(from); err != nil {
return err
}
for _, recp := range to {
祝老师新年快乐if err := validateLine(recp); err != nil {
return err
}
}
c, err := Dial(addr)
假面骑士迦武斗if err != nil {
return err
}
defer c.Close()
if err = c.hello(); err != nil {
return err
}
if ok, _ := c.Extension("STARTTLS"); ok {
/
/ 跳过证书验证
config := &tls.Config{ServerName: c.serverName, InsecureSkipVerify: true}
if testHookStartTLS != nil {
testHookStartTLS(config)
}
if err = c.StartTLS(config); err != nil {
return err
}
}
if a != nil && c.ext != nil {
if _, ok := c.ext["AUTH"]; !ok {
return errors.New("smtp: server doesn't support AUTH")
}
if err = c.Auth(a); err != nil {
return err
}
}
if err = c.Mail(from); err != nil {
return err
}
for _, addr := range to {
if err = c.Rcpt(addr); err != nil {
return err全家福怎么获得
}
}
w, err := c.Data()
if err != nil {
return err
}
_, err = w.Write(msg)
if err != nil {
return err
}
err = w.Close()
if err != nil {
return err
文科男生学什么专业好
}
return c.Quit()
}
另外原来smtp包⾥还有,这个⽂件也要⼀并复制到mySmtp包⾥现在main函数⾥⾯smtp的调⽤都变成我们mySmtp包,运⾏之后
504 this command is not implemented

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。