1. 程式人生 > >電子郵件協議及GO傳送QQ郵件

電子郵件協議及GO傳送QQ郵件

[TOC] ### 一、電子郵件的工作機制 ![image-20200531204042406](https://img2020.cnblogs.com/blog/1496926/202005/1496926-20200531224213873-879729387.png) 提供電子郵件服務的協議叫做:**SMTP(Simple Mail Transfer Protocol)**為了能夠高效安全的進行資料的傳輸,SMTP協議底層使用的TCP實現兩端的連線。 早期的電子郵件收發的工作機制如上圖所示。傳送端和接收端之間通過SMTP底層的TCP簡歷連線。通過網路直接將郵件傳送到對方的磁碟上。 但是問題也隨之而來: ![image-20200531204517018](https://img2020.cnblogs.com/blog/1496926/202005/1496926-20200531224214620-2097006688.png) 如果接收方沒有開機,或者開機了但是沒有連線網路,那麼就不能通過SMTP協議建立連線,這時傳送端只能是個隔一段時間後重試,直到接收端開機了,聯網了,傳送端才能成功的將郵件傳送給接收方。問題很明顯,接收方只要不開機,傳送方的郵件就不能傳送出去,如果是東方國家和西方國家之間的兩個人各自在各自的白天才開機,那豈不是他們之間的郵件根本不可能傳送出去了? 為了解決這個問題,郵件伺服器出現了: ![image-20200531205111380](https://img2020.cnblogs.com/blog/1496926/202005/1496926-20200531224215036-591076866.png) 這時收發郵件的工作機制就演變成了上圖那樣。傳送方 面向 郵件伺服器傳送郵件,而不管接收方是否開機,是否聯網,接收方通過上線後使用POP3(Post Office Proto-col)從郵件伺服器接收郵件。 整個過程中,郵件伺服器是不會斷電的。 #### 1.1 SMTP 通過上圖可以看到,SMTP是傳送電子郵件時使用的協議。 它底層使用tcp的25號埠。在這個tcp連線上進行控制,應答,以及資料的傳輸。 客戶端以文字的方式傳送請求,郵件伺服器每次回覆3位數字作為應答。比如客戶端首次會發送 `HELO`表示請求建立連線。正常的話郵件伺服器會回覆250,表示完成請求命令。 SMTP協議中規定,以'.'最為郵件正文的結束符。當正文前面有一個'.'或者有兩個'.' 都要進行特殊處理。 SMTP不會校驗傳送者,所以我們經常會收到垃圾郵件,據說也會有“POP before SMTP” 和“SMTP認證”機制,來防止冒充發送人。從而減少垃圾郵件的數量。 #### 1.2 POP3 POP伺服器也是一臺一直處於充電狀態的伺服器。 客戶端通過pop3協議從pop伺服器上接收發送方發過來的協議,但是在接收之前是需要進行使用者身份驗證的,也就是說,客戶端得將自己的賬號密碼傳送到POP伺服器,通過驗證後才能取回屬於自己的郵件 POP與SMTP一樣,都是基於TCP連線完成相應的操作的。 #### 1.3 IMAP IMAP和POP協議一樣都是接收電子郵件時使用的協議。 如果使用IMAP,即使不用將電子郵件下載到本地也可以閱讀。因為IMAP實現了字啊服務端處理MIME型別的資料,所以他能實現當一封電子郵件有10個附件時,它能直接開啟其中的某一個。而且在服務端作出已讀/未讀,等狀體的修改。 ### 二、郵件地址 郵件地址通常都是由兩部分組成: `名稱@地址`。 常見的像 `[email protected]` 這種郵件的地址。 123就是名稱,qq.com就是地址。 電子郵件的地址和域名構造相同,後面的com是頂級域名。 現在的電子郵件地址由DNS統一管理。DNS裡面儲存著各個郵件地址,和這個郵件地址作為傳送地址時所對應的郵件伺服器的域名資訊。我們把這種對映關係稱為MX記錄。因為方才說了,對現在的郵件傳送機制來說,傳送者是將郵件傳送到郵件伺服器上。那通過查詢DNS中的MX記錄,就能知道` [email protected]. `和` [email protected]` 這種不同的郵件字尾所對應的郵件伺服器的域名,通過域名進一步找到這個機器。 ### 三、MIME資訊 最初的很長一段時間裡,郵件只能傳送文字資訊。後臺能傳送的資料型別已經被拓展到了MIME。可以傳送諸如gif, video,png,jpg,jpeg,text/plain 等等型別的資料。具體傳送啥樣的資訊,通過Content-Type定義。 ### 四、使用golang傳送qq郵件 例項程式碼如下: ```go package mail import ( "strconv" ) import "gopkg.in/gomail.v2" func SendMail(mailTo []string, subject string, body string) error { mailConn := map[string]string{ "user": "[email protected]", // 郵件傳送者的地址 "pass": "trsxxxxxxxxxxcd", // qq郵箱填授權碼,百度一下獲取方式。 "host": "smtp.qq.com", // 傳送將郵件傳送給騰訊的smtp郵件伺服器 "port": "465", // 傳送郵件使用的埠 } port, _ := strconv.Atoi(mailConn["port"]) m := gomail.NewMessage() m.SetHeader("From", m.FormatAddress(mailConn["user"], "自動化成績查詢")) 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 } /* 傳送郵件 stuEmail:學生的郵箱 subject:標題 body:傳送的內容 */ func DoSendMail(stuEmail , subject, body string) (e error) { mailTo := []string{stuEmail} err := SendMail(mailTo, subject, body) if err != nil { e = err return e } return nil } //func main() { // //定義收件人 // mailTo := []string{ // "[email protected]", // "[email protected]", // } // //郵件主題為"Hello" // subject := "Hi 出成績了" // // 郵件正文 // body := "請查收您的新成績" // // err := SendMail(mailTo, subject, body) // if err != nil { // log.Println(err) // fmt.Println("send fail") // return // } // fmt.Println("send successfully")