SMTP 全名為Simple Mail Transfer Protocol 簡單郵件傳輸協議,它是郵件服務器用來在電子郵件發件人和收件人之間發送、接收和/或中繼外發郵件的應用程序。
SMTP 電子郵件服務器將有一個地址(或多個地址),可由您使用的郵件客戶端或應用程序設置,通常格式為 smtp.serveraddress.com。例如,Gmail 的 SMTP 服務器主機地址為 smtp.gmail.com,Twilio SendGrid 的為 smtp.sendgrid.com。您通常可以在郵件客戶端的帳戶或設置部分中找到您的 SMTP 電子郵件服務器地址。
當您發送電子郵件時,SMTP 服務器會處理您的電子郵件,決定將消息發送到哪個服務器,並將消息中繼到該服務器。收件人的收件箱服務提供商(例如 Gmail 或 AOL)會下載郵件並將其放入收件人的收件箱中。
理論上是的,他與一般大多伺服器相同,SMTP 服務器處理要發送到另一台服務器的數據,但它具有處理與電子郵件發送、接收和中繼相關的數據的非常具體的目的。SMTP 服務器也不一定在機器上。它是一個不斷運行以期待發送新郵件的應用程序。
這邊我們使用"net/smtp"
這個官方的標準庫來實現功能。
app/service/smtp.go
package service
import (
"github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"ironman-2021/app/middleware"
"net/smtp"
"os"
)
func Send(title string, body string, to string) {
envErr := godotenv.Load()
if envErr != nil {
panic(envErr)
}
from := os.Getenv("MAIL_USERNAME")
pass := os.Getenv("MAIL_PASSWORD")
port := os.Getenv("MAIL_PORT")
server := os.Getenv("MAIL_SERVER")
msg := "From: " + from + "\n" +
"To: " + to + "\n" +
"Subject: " + title + "\n" +
body
err := smtp.SendMail(server + ":" + port,
smtp.PlainAuth("", from, pass, server),
from, []string{to}, []byte(msg))
if err != nil{
middleware.Logger().WithFields(logrus.Fields{
"name": "Smtp",
}).Error("error: ", err)
return
}
middleware.Logger().WithFields(logrus.Fields{
"name": "Smtp",
}).Info("Send from: ", from + ", To: ", to)
}
MAIL_USERNAME
, MAIL_PASSWORD
, MAIL_PORT
與MAIL_SERVER
都給load進function來使用。app/controller/user.go
這邊我們則是在創建新使用者成功時,發送一封提醒信。
// CreateUser @Summary
// @Tags user
// @version 1.0
// @produce application/json
// @param language header string true "language"
// @param register body Register true "register"
// @Success 200 string successful return value
// @Router /v1/users [post]
func (u UsersController) CreateUser(c *gin.Context) {
t := gi18n.New()
var form Register
bindErr := c.BindJSON(&form)
lan := c.Request.Header.Get("language")
if lan == "" {
lan = "en"
}
t.SetLanguage(lan)
if bindErr == nil {
err := service.RegisterOneUser(form.Account, form.Password, form.Email)
if err == nil {
service.Send("Register Notification", "Welcome to become our membership", form.Email)
c.JSON(http.StatusOK, gin.H{
"status": 1,
"msg": t.Translate(c, "Response_Success"),
"data": nil,
})
} else {
c.JSON(http.StatusInternalServerError, gin.H{
"status": -1,
"msg": "Register Failed" + err.Error(),
"data": nil,
})
}
} else {
c.JSON(http.StatusBadRequest, gin.H{
"status": -1,
"msg": "Failed to parse register data" + bindErr.Error(),
"data": nil,
})
}
}
最後使用者則會收到一封類似下方的mail,同時我們在log也能看到發送成功的信息。
time="131310-10-10 1010:1010:1010" level=info msg="Send from: ghjjhg567@gmail.com, To: ghjjhg567@gmail.com" name=Smtp
time="131310-10-10 1010:1010:1010" level=info msg="| 200 | 5.7536937s | 192.168.144.1 | POST | /v1/users/ |"
這章節我們實作了如何以smtp轉發信件,但這邊也遇到了一個小問題,那就是我們因為要等待smtp轉發完畢才會將response回給client端,因此我們的response time變長了許多。也因此在下個章節我們要將現行架構結合async
來創造一個更好的使用者體驗。
這次的程式碼我也會放在下方連結提供參考。
https://github.com/Neskem/Ironman-2021/tree/Day-28