Go 每日一庫之 email

簡介

程序中時常有發送郵件的需求。有異常狀況了須要通知管理員和負責人,用戶下單後可能須要通知訂單信息,電商平臺、中國移動和聯通都有每個月帳單,這些均可以經過郵件來推送。還有咱們平時收到的垃圾郵件大都也是經過這種方式發送的😭。那麼如何在 Go 語言發送郵件?本文咱們介紹一下email庫的使用。git

快速使用

這個庫的使用快不了,爲何呢?github

先安裝庫,這個自沒必要說:golang

$ go get github.com/jordan-wright/email
複製代碼

咱們須要額外一些工做。咱們知道郵箱使用SMTP/POP3/IMAP等協議從郵件服務器上拉取郵件。郵件並非直接發送到郵箱的,而是郵箱請求拉取的。 因此,咱們須要配置SMTP/POP3/IMAP服務器。從頭搭建當然可行,並且也有現成的開源庫,可是比較麻煩。如今通常的郵箱服務商都開放了SMTP/POP3/IMAP服務器。 我這裏拿 126 郵箱來舉例,使用SMTP服務器。固然,用 QQ 郵箱也能夠。web

  • 首先,登陸郵箱;
  • 點開頂部的設置,選擇POP3/SMTP/IMAP
  • 點擊開啓IMAP/SMTP服務,按照步驟開啓便可,有個密碼設置,記住這個密碼,後面有用。

而後就能夠編碼了:安全

package main

import (
  "log"
  "net/smtp"

  "github.com/jordan-wright/email"
)

func main() {
  e := email.NewEmail()
  e.From = "dj <xxx@126.com>"
  e.To = []string{"935653229@qq.com"}
  e.Subject = "Awesome web"
  e.Text = []byte("Text Body is, of course, supported!")
  err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "xxx@126.com", "yyy", "smtp.126.com"))
  if err != nil {
    log.Fatal(err)
  }
}
複製代碼

這裏爲了個人信息安全,我把真實信息都隱藏了。代碼中xxx替換成你的郵箱帳號,yyy替換成上面設置的密碼。服務器

代碼步驟比較簡單清晰:微信

  • 先調用NewEmail建立一封郵件;
  • 設置From發送方,To接收者,Subject郵件主題(標題),Text設置郵件內容;
  • 而後調用Send發送,參數1是 SMTP 服務器的地址,參數2爲驗證信息。

運行程序將會向個人 QQ 郵箱發送一封郵件:網絡

有的郵箱會把這種郵件放在垃圾箱中,例如 QQ😭。若是收件箱找不到,記獲得垃圾箱瞅瞅。性能

抄送

日常咱們發郵件的時候可能會抄送給一些人,還有一些人要祕密抄送😄,即 CC(Carbon Copy)和 BCC (Blind Carbon Copy)。 email咱們也能夠設置這兩個參數:學習

package main

import (
  "log"
  "net/smtp"

  "github.com/jordan-wright/email"
)

func main() {
  e := email.NewEmail()
  e.From = "dj <xxx@126.com>"
  e.To = []string{"935653229@qq.com"}
  e.Cc = []string{"test1@126.com", "test2@126.com"}
  e.Bcc = []string{"secret@126.com"}
  e.Subject = "Awesome web"
  e.Text = []byte("Text Body is, of course, supported!")
  err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "xxx@126.com", "yyy", "smtp.126.com"))
  if err != nil {
    log.Fatal(err)
  }
}
複製代碼

仍是同樣的,抄送的郵箱本身替換test1/test2/secret用本身的。

運行程序將會向個人 QQ 郵件發送一封郵件,同時抄送一封到我另外一個 126 郵箱:

HTML 格式

發送純文本,郵件不太美觀。email支持發送 HTML 格式的內容。與發送純文本相似,直接設置對象的HTML字段:

package main

import (
  "log"
  "net/smtp"

  "github.com/jordan-wright/email"
)

func main() {
  e := email.NewEmail()
  e.From = "dj <xxx@126.com>"
  e.To = []string{"935653229@qq.com"}
  e.Cc = []string{"xxx@126.com"}
  e.Subject = "Go 每日一庫"
  e.HTML = []byte(` <ul> <li><a "https://darjun.github.io/2020/01/10/godailylib/flag/">Go 每日一庫之 flag</a></li> <li><a "https://darjun.github.io/2020/01/10/godailylib/go-flags/">Go 每日一庫之 go-flags</a></li> <li><a "https://darjun.github.io/2020/01/14/godailylib/go-homedir/">Go 每日一庫之 go-homedir</a></li> <li><a "https://darjun.github.io/2020/01/15/godailylib/go-ini/">Go 每日一庫之 go-ini</a></li> <li><a "https://darjun.github.io/2020/01/17/godailylib/cobra/">Go 每日一庫之 cobra</a></li> <li><a "https://darjun.github.io/2020/01/18/godailylib/viper/">Go 每日一庫之 viper</a></li> <li><a "https://darjun.github.io/2020/01/19/godailylib/fsnotify/">Go 每日一庫之 fsnotify</a></li> <li><a "https://darjun.github.io/2020/01/20/godailylib/cast/">Go 每日一庫之 cast</a></li> </ul> `)
  err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "xxx@126.com", "yyy", "smtp.126.com"))
  if err != nil {
    log.Fatal("failed to send email:", err)
  }
}
複製代碼

發送結果:

注意,126 的 SMTP 服務器檢測比較嚴格,加上 HTML 以後,很容易被識別爲垃圾郵件不讓發送,這時 CC 本身就 OK 了。

附件

添加附件也很容易,直接調用AttachFile便可:

package main

import (
  "log"
  "net/smtp"

  "github.com/jordan-wright/email"
)

func main() {
  e := email.NewEmail()
  e.From = "dj <xxx@126.com>"
  e.To = []string{"935653229@qq.com"}
  e.Subject = "Go 每日一庫"
  e.Text = []byte("請看附件")
  e.AttachFile("test.txt")
  err := e.Send("smtp.126.com:25", smtp.PlainAuth("", "xxx@126.com", "yyy", "smtp.126.com"))
  if err != nil {
    log.Fatal("failed to send email:", err)
  }
}
複製代碼

收到的郵件:

鏈接池

實際上每次調用Send時都會和 SMTP 服務器創建一次鏈接,若是發送郵件不少很頻繁的話可能會有性能問題。email提供了鏈接池,能夠複用網絡鏈接:

package main

import (
  "fmt"
  "log"
  "net/smtp"
  "os"
  "sync"
  "time"

  "github.com/jordan-wright/email"
)

func main() {
  ch := make(chan *email.Email, 10)
  p, err := email.NewPool(
    "smtp.126.com:25",
    4,
    smtp.PlainAuth("", "leedarjun@126.com", "358942617ldj", "smtp.126.com"),
  )

  if err != nil {
    log.Fatal("failed to create pool:", err)
  }

  var wg sync.WaitGroup
  wg.Add(4)
  for i := 0; i < 4; i++ {
    go func() {
      defer wg.Done()
      for e := range ch {
        err := p.Send(e, 10*time.Second)
        if err != nil {
          fmt.Fprintf(os.Stderr, "email:%v sent error:%v\n", e, err)
        }
      }
    }()
  }

  for i := 0; i < 10; i++ {
    e := email.NewEmail()
    e.From = "dj <leedarjun@126.com>"
    e.To = []string{"935653229@qq.com"}
    e.Subject = "Awesome web"
    e.Text = []byte(fmt.Sprintf("Awesome Web %d", i+1))
    ch <- e
  }

  close(ch)
  wg.Wait()
}
複製代碼

上面程序中,咱們建立 4 goroutine 共用一個鏈接池發送郵件,發送 10 封郵件後程序退出。爲了等郵件都發送完成或失敗,程序才退出,咱們使用了sync.WaitGroup

郵箱被轟炸了:

因爲使用了 goroutine,郵件順序不能保證。

總結

本文介紹瞭如何使用 Go 程序發送郵件,程序代碼都已經放在 GitHub 上github.com/darjun/go-d…。全部代碼都經過測試,你們請放心食用~

你們若是發現好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue😄

參考

  1. email GitHub:github.com/jordan-wrig…
  2. Go 每日一庫 GitHub:github.com/darjun/go-d…

個人博客

歡迎關注個人微信公衆號【GoUpUp】,共同窗習,一塊兒進步~

本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索