依據 smtp協議的簡單golang 的發郵件實現

依據 smtp協議的簡單golang 的發郵件實現

協議格式以下git

From:sender_user@demo.net
To:to_user@demo.net
Subject:這是主題
Mime-Version:1.0 //一般是1.0
Content-Type:Multipart/mixed;Boundary="THIS_IS_BOUNDARY_JUST_MAKE_YOURS" //boundary爲分界字符,跟http傳文件時相似
Date:當前時間


--THIS_IS_BOUNDARY_JUST_MAKE_YOURS         //boundary前邊須要加上鍊接符 -- , 首部和第一個boundary之間有兩個空行
Content-Type:text/plain;chart-set=utf-8
                                            //單個部分的首部和正文間有個空行
這是正文1
這是正文2

--THIS_IS_BOUNDARY_JUST_MAKE_YOURS                  //每一個部分的與上一部分之間一個空行
Content-Type:image/jpg;name="test.jpg"
Content-Transfer-Encoding:base64
Content-Description:這個是描述
                                            //單個部分的首部和正文間有個空行
base64編碼的文件                              //文件內容使用base64 編碼,單行不超過80字節,須要插入\r\n進行換行
--THIS_IS_BOUNDARY_JUST_MAKE_YOURS--        //最後結束的標識--boundary--

golang 代碼實現以下github

//email/email.gogolang

package email

import (
    "bytes"
    "encoding/base64"
    "fmt"
    "io/ioutil"
    "net/smtp"
    "strings"
    "time"
)

//SendEmailWithAttachment : send email with attachment
func SendEmailWithAttachment(user, passwd, host, to, subject string) error {
    hp := strings.Split(host, ":")
    auth := smtp.PlainAuth("", user, passwd, hp[0])
    buffer := bytes.NewBuffer(nil)

    boudary := "THIS_IS_BOUNDARY_JUST_MAKE_YOURS"
    header := fmt.Sprintf("To:%s\r\n"+
        "From:%s\r\n"+
        "Subject:%s\r\n"+
        "Content-Type:multipart/mixed;Boundary=\"%s\"\r\n"+
        "Mime-Version:1.0\r\n"+
        "Date:%s\r\n", to, user, subject, boudary, time.Now().String())
    buffer.WriteString(header)
    fmt.Print(header)

    msg1 := "\r\n\r\n--" + boudary + "\r\n" + "Content-Type:text/plain;charset=utf-8\r\n\r\n這是正文啊\r\n"

    buffer.WriteString(msg1)
    fmt.Print(msg1)

    msg2 := fmt.Sprintf(
        "\r\n--%s\r\n"+
            "Content-Transfer-Encoding: base64\r\n"+
            "Content-Disposition: attachment;\r\n"+
            "Content-Type:image/jpg;name=\"test.jpg\"\r\n", boudary)
    buffer.WriteString(msg2)
    fmt.Print(msg2)

    attachmentBytes, err := ioutil.ReadFile("./test.jpg")
    if err != nil {
        fmt.Println("ReadFile ./test.jpg Error : " + err.Error())
        return err
    }
    b := make([]byte, base64.StdEncoding.EncodedLen(len(attachmentBytes)))
    base64.StdEncoding.Encode(b, attachmentBytes)
    buffer.WriteString("\r\n")
    fmt.Print("\r\n")
    fmt.Print("圖片base64編碼")
    for i, l := 0, len(b); i < l; i++ {
        buffer.WriteByte(b[i])
        if (i+1)%76 == 0 {
            buffer.WriteString("\r\n")
        }
    }

    buffer.WriteString("\r\n--" + boudary + "--")
    fmt.Print("\r\n--" + boudary + "--")

    sendto := strings.Split(to, ";")
    err = smtp.SendMail(host, auth, user, sendto, buffer.Bytes())

    return err
}

//email_test.go測試

package email

import "testing"

func TestSendEmailWithAttachment(t *testing.T) {
    err := SendEmailWithAttachment("xx@example.com", "passwd", "smtp.xx.com:25", "xx@example.com", "測試附件")
    if err != nil {
        t.Fatal(err)
    }
}

go test 打印輸出以下編碼

To:xx@example.com
From:xx@example.com
Subject:測試附件
Content-Type:multipart/mixed;Boundary="THIS_IS_BOUNDARY_JUST_MAKE_YOURS"
Mime-Version:1.0
Date:2016-09-11 12:17:37.268146477 +0800 CST


--THIS_IS_BOUNDARY_JUST_MAKE_YOURS
Content-Type:text/plain;charset=utf-8

這是正文啊

--THIS_IS_BOUNDARY_JUST_MAKE_YOURS
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
Content-Type:image/jpg;name="test.jpg"

圖片base64編碼
--THIS_IS_BOUNDARY_JUST_MAKE_YOURS--

部分實現參考 https://github.com/scorredoira/email 具體項目中可以使用該庫。.net

遇到的問題code

  1. 對boundary格式理解錯誤,頭部寫的boundary 在下邊用的時候要拼上--前綴
  2. 含有附件的,第一個boundary 和 header 中間有兩個空行
  3. 結束標記爲 --boundary--
  4. 循環文件內容進行插入換行時,若是出現邏輯錯誤,則傳輸的附件顯示異常,沒法正常查看和下載。
相關文章
相關標籤/搜索