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


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

協議格式如下

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 代碼實現如下

//email/email.go

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 具體項目中可使用該庫。

遇到的問題

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM