Go 语言使用阿里云企业邮箱发送 SMTP 邮件

yufei       4 年 前       3287

Go 语言提供了 net/smtp 来发送邮件,但是这个 API 有点底层,如果要发送一封带附件的 HTML 邮件自己要写好多东西。

得益于 net/smtp ABI 的稳定,有一个第三方库 gopkg.in/gomail.v2 封装的还不错,用来发送邮件也简单。

发送单封邮件

使用 gopkg.in/gomail.v2 发送邮件一般有 9 个步骤,分别如下

  1. 首先构建一个 Message 对象,也就是邮件对象
  2. 填充发件人 From
  3. 填充收件人 To
  4. 填充抄送 Cc
  5. 设置邮件标题 Subject
  6. 设置邮件正文
  7. 如果有需要,可以添加附件
  8. 实例化一个邮件发送器
  9. 连接到邮件服务器并发送
package main

import (
    mailer "gopkg.in/gomail.v2"
)

func main() {
    // 1. 首先构建一个 Message 对象,也就是邮件对象
    msg := mailer.NewMessage()
    // 2. 填充 From,注意第一个字母要大写
    msg.SetHeader("From", "from_address@example.com")
    // 3. 填充 To
    msg.SetHeader("To", "to_address@example.com")
    // 4. 如果需要可以填充 cc,也就是抄送
    msg.SetHeader("Cc", "cc_address@example.com")
    // 5. 设置邮件标题
    msg.SetHeader("Subject", "Go 语言发送邮件")
    // 6. 设置要发送的邮件正文
    // 第一个参数是类型,第二个参数是内容
    // 如果是 html,第一个参数则是 `text/html`
    msg.SetBody("text/html", "<h3>欢迎来到简单教程</h3><p>简单教程,简单编程</p>")
    // 7. 添加附件,注意,这个附件是完整路径
    //msg.Attach("/Users/yufei/Downloads/1.jpg")

    // 到此,邮件消息构建完毕
    // 8. 创建 smtp 实例
    // 如果你的阿里云企业邮箱则是密码,否则一般情况下国内国外使用的都是授权码
    dialer := mailer.NewDialer("smtp.mxhichina.com", 465, "阿里云企业邮箱账号", "阿里云企业邮箱密码")
    // 9. 发送邮件,连接邮件服务器,发送完就关闭
    if err := dialer.DialAndSend(msg); err != nil {
        panic(err)
    }

}

发送多封邮件

DialAndSend() 方法是一次性的,也就是连接邮件服务器,发送邮件,然后关闭连接。

如果你有很多封邮件要发,那么正确的方法应该是 创建一个连接器,然后不断的发,准确的说,就是下面这个例子

package main

import (
    mailer "gopkg.in/gomail.v2"
    "log"
)

type Address struct {
    Name, Address string
}

func main() {

    // 先连接到邮件服务器
    dialer := mailer.NewDialer("smtp.mxhichina.com", 465, "阿里云企业邮箱账号", "阿里云企业邮箱密码")
    sock, err := dialer.Dial()
    if err != nil {
        panic(err)
    }

    // 收件人
    list := []Address{
        Address{Name: "简单教程", Address: "to@example.com"},
        Address{Name: "简单教程2", Address: "to2@example.com"},
    }

    // 然后发送多封邮件
    msg := mailer.NewMessage()
    for _, r := range list {
        msg.SetHeader("From", "from_address@example.com")
        msg.SetHeader("To", msg.FormatAddress(r.Address, r.Name))
        msg.SetHeader("Subject", "Go 语言发送邮件")
        msg.SetBody("text/html", "<h3>欢迎来到简单教程</h3><p>简单教程,简单编程</p>")

        if err := mailer.Send(sock, msg); err != nil {
            log.Printf("Could not send email to %q: %v", r.Address, err)
        }
        // 千万不要忘记调用这个
        msg.Reset()
    }
}

创建一个服务,用来发送邮件

正式环境中,我们一般会用管道 channel 来创建一个邮件发送服务,也就是类似下面这样

package main

import (
    mailer "gopkg.in/gomail.v2"
    "log"
    "time"
)

type Address struct {
    Name, Address string
}

func main() {

    // 收件人
    list := []Address{
        Address{Name: "简单教程", Address: "to@example.com"},
        Address{Name: "简单教程2", Address: "to2@example.com"},
    }

    ch := make(chan *mailer.Message)

    go func() {
        dialer := mailer.NewDialer("smtp.mxhichina.com", 465, "阿里云企业邮箱账号", "阿里云企业邮箱密码")
        var sock mailer.SendCloser
        var err error
        var lasted int64 = 0
        open := false
        for {
            select {
            case msg, ok := <-ch:
                log.Printf("%v\n", msg)
                if !ok {
                    return
                }
                if !open {
                    if sock, err = dialer.Dial(); err != nil {
                        panic(err)
                    }
                    open = true
                }
                if err := mailer.Send(sock, msg); err != nil {
                    lasted = time.Now().Unix()
                    log.Printf("发送错误:%s\n", err.Error())
                }
            // 如果 30s 没有再发送邮件则关闭
            case <-time.Tick(30 * time.Second):
                if open && time.Now().Unix()- lasted > 30 {
                    log.Printf("30 秒没有任何邮件,直接关闭")
                    if err := sock.Close(); err != nil {
                        panic(err)
                    }
                    open = false
                }
            }
        }
    }()

    // 然后发送多封邮件

    for _, r := range list {
        msg := mailer.NewMessage()
        msg.SetHeader("From", "from_address@example.com")
        msg.SetHeader("To", msg.FormatAddress(r.Address, r.Name))
        msg.SetHeader("Subject", "Go 语言发送邮件")
        msg.SetBody("text/html", "<h3>欢迎来到简单教程</h3><p>简单教程,简单编程</p>")
        ch <- msg
    }

    time.Sleep(120 * time.Second)
    // 程序接受后关闭管道
    close(ch)

}
  1. time.Sleep(120 * time.Second) 用来防止命令行退出
  2. close(ch) 一定要在 Sleep() 之后调用,否则没有效果
  3. 使用 time.Tick() 来做心跳检测
目前尚无回复
简单教程 = 简单教程,简单编程
简单教程 是一个关于技术和学习的地方
现在注册
已注册用户请 登入
关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.