需求

最近做的项目上需要在做了某项任务之后发邮件出来通知。于是开始调查怎么用golange 代码发送邮件。

调查

搜索一番发现有 net/smtpjordan-wrightgomail三个库可以使用,那就让我们挑一个试试吧。

编码测试

使用 net/smtp库

废话不多说,直接上代码

package main

import (
        "github.com/jordan-wright/email"
        "log"
        "net/smtp"
)

const (
        SMTPHost     = "smtp.gmail.com"
        SMTPPort     = ":587"
        SMTPUsername = "xxx@gmail.com"
        SMTPPassword = "xxxx"
)

func main() {
        sendEmail()
}

func sendEmail() {
        log.Println("send email")
        receiver := "xxx@gmial.com"
        auth := smtp.PlainAuth("", SMTPUsername, SMTPPassword, SMTPHost)
        msg := []byte("Subject: here is the subject \r\n\r\n" + "这里是正文内容\r\n")
        err := smtp.SendMail(SMTPHost+SMTPPort, auth, SMTPUsername, []string{receiver}, msg)
        if err != nil {
                log.Println("failed to send email:", err)
        }
}

但是使用之后发现报错了

504 5.7.4 Unrecognized authentication type

bing 和 google 搜索了一番没有查到解决办法,于是尝试了另一个库

使用 net/smtp库

package main

import (
        "crypto/tls"
        "fmt"
        "github.com/jordan-wright/email"
        "log"
        "net/smtp"
)

const (
        SMTPHost     = "smtp.gmail.com"
        SMTPPort     = ":587"
        SMTPUsername = "xxx@gmail.com"
        SMTPPassword = "xxxx"
)

func main() {
        sendEmailJordan()
}

func sendEmailJordan() {
        log.Println("send email with jordan")
        receiver := "xxx@gmail.com"

        auth := smtp.PlainAuth("", SMTPUsername, SMTPPassword, SMTPHost)
        e := &email.Email{
                From:    fmt.Sprintf("发送者名字<%s>", SMTPUsername),
                To:      []string{receiver},
                Subject: "这里是标题内容",
                Text:    []byte("这里是正文内容"),
        }
        //func (e *Email) Send(addr string, a smtp.Auth) error {
        err := e.Send(SMTPHost+SMTPPort, auth)
        if err != nil {
                log.Println("failed to Send email with jordan:", err)
        }

        //tc:=&tls.Config{InsecureSkipVerify: true}
        tc := &tls.Config{
                ServerName:         SMTPHost,
                InsecureSkipVerify: true,
        }
        err = e.SendWithStartTLS(SMTPHost+SMTPPort, auth, tc)
        if err != nil {
                log.Println("failed to SendWithStartTLS email with jordan:", err)
        }
}

因为我们的邮箱服务是StartTLS 加密方式,我还试了 SendWithStartTLS() 方法,但同样都是报 Unrecognized authentication 错误。 找了好久都没找到解法,我相信解决办法一定是有的,只是暂时我没有找到,有大佬知道怎么解决的,欢迎给我留言评论,不胜感激。

使用 gomail

报错解不掉,于是接着尝试其他方法,本来不太抱希望的,居然成功了! 先下载gomail 包 go get gopkg.in/gomail.v2 代码:

package main

import (
        "fmt"
        "gopkg.in/gomail.v2"
        "log"
        "strconv"
)

const (
        SMTPHost     = "smtp.gmail.com"
        SMTPPort     = ":587"
        SMTPUsername = "xxx@gmail.com"
        SMTPPassword = "xxxx"
)


func SendMail(mailTo []string, subject string, body string) error {
        // 设置邮箱主体
        mailConn := map[string]string{
                "user": SMTPUsername,
                "pass": SMTPPassword,
                "host": SMTPHost,
                "port": SMTPPort,
        }

        port, _ := strconv.Atoi(mailConn["port"])
        m := gomail.NewMessage()
        m.SetHeader("From", m.FormatAddress(mailConn["user"], "xx官方"))                   // 添加别名
        m.SetHeader("To", mailTo...)                                                      // 发送给用户(可以多个)
        m.SetHeader("Subject", subject)                                                   // 设置邮件主题
        m.SetBody("text/html", body)                                                      // 设置邮件正文
        d := gomail.NewDialer(mailConn["host"], port, mailConn["user"], mailConn["pass"]) // 设置邮件正文
        err := d.DialAndSend(m)
        return err
}

func main() {
        // 发送方
        mailTo := []string{
                "xxx<xxx@gmail.com>", // 这里最好写成邮箱收发件时的这种标记格式
        }
        // 邮件主题
        subject := "Hello"
        // 邮件正文
        body := "Automatic send by Go gomail from xxx官方."
        err := SendMail(mailTo, subject, body)
        if err != nil {
                log.Print(err)
                fmt.Printf("Send fail!")
                return
        }
        fmt.Println("send successfully!")
}

这份代码中并没有出现tls 相关的关键字,但是居然发送成功了! 我相信前两种方法应该也是能成功的,目前我还没有找到解决 Unrecognized authentication 错误的方法,希望有大佬指教一下。

参考链接

  1. GoLang 中发送 email 邮件
  2. 使用gomail发送邮件 - - 避坑