天天看點

Golang 通過net/smtp發送郵件 在正文中添加圖檔(附件/非附件)

背景

遇到一個需求 需要發送帶有圖檔的郵件

于是參考:http://www.cnblogs.com/zengchunyun/p/9485444.html

完成了帶圖檔附件的郵件發送功能

但是!!

産品竟然說 圖檔需要在正文裡!!正文!! 個人覺得在附件裡很好呀0.0

**嘗試**

産品說什麼就是什麼吧。。

于是瘋狂嘗試怎麼把圖檔從附件裡顯示到正文當中

multipart類型,有三種子類型:mixed、alternative、related

multipart/mixed可以包含附件。

multipart/related可以包含内嵌資源。

multipart/alternative 純文字與超文本共存

multipart可以發送若幹個内容 并使用boundary來分割

一開始以為是mixed的緣故 改成了related

但是一點都沒用。。該在附件裡的還是出現在了附件了

最後自己本地發郵件抓包 發現了原來可以發送html格式的郵件 把圖檔放到‘’img‘’中來實作正文中添加圖檔的功能

廢話不多說 上代碼

**代碼** ```golang package main

import (

“bytes”

“encoding/base64”

“fmt”

“io/ioutil”

“net/smtp”

“strings”

“time”

)

type SendMail struct {

user string

password string

host string

port string

auth smtp.Auth

}

type Attachment struct {

name []string

contentType string

withFile bool

}

type Message struct {

from string

to []string

cc []string

bcc []string

subject string

body string

contentType string

attachment Attachment

}

func (mail *SendMail) Auth() {

mail.auth = smtp.PlainAuth("", mail.user, mail.password, mail.host)

}

func (mail SendMail) Send(message Message) error {

mail.Auth()

buffer := bytes.NewBuffer(nil)

boundary := “GoBoundary”

Header := make(map[string]string)

Header[“From”] = message.from

Header[“To”] = strings.Join(message.to, “;”)

Header[“Cc”] = strings.Join(message.cc, “;”)

Header[“Bcc”] = strings.Join(message.bcc, “;”)

Header[“Subject”] = message.subject

Header[“Content-Type”] = “multipart/related;boundary=” + boundary

Header[“Date”] = time.Now().String()

mail.writeHeader(buffer, Header)

var imgsrc string
if message.attachment.withFile {
	//多圖檔發送
	for _, graphname := range message.attachment.name {
		attachment := "\r\n--" + boundary + "\r\n"
		attachment += "Content-Transfer-Encoding:base64\r\n"
		attachment += "Content-Type:" + message.attachment.contentType + ";name=\"" + graphname + "\"\r\n"
		attachment += "Content-ID: <" + graphname + "> \r\n\r\n"
		buffer.WriteString(attachment)
		
		//拼接成html
		imgsrc += "<p><img src=\"cid:" + graphname + "\" height=200 width=300></p><br>\r\n\t\t\t"

		defer func() {
			if err := recover(); err != nil {
				fmt.Printf(err.(string))
			}
		}()
		mail.writeFile(buffer, graphname)
	}
}

//需要在正文中顯示的html格式
var template = `
<html>
	<body>
		<p>text:%s</p><br>
		%s			
	</body>
</html>
`
var content = fmt.Sprintf(template, message.body, imgsrc)
body := "\r\n--" + boundary + "\r\n"
body += "Content-Type: text/html; charset=UTF-8 \r\n"
body += content
buffer.WriteString(body)

buffer.WriteString("\r\n--" + boundary + "--")
fmt.Println(buffer.String())
smtp.SendMail(mail.host+":"+mail.port, mail.auth, message.from, message.to, buffer.Bytes())
return nil
           

}

func (mail SendMail) writeHeader(buffer *bytes.Buffer, Header map[string]string) string {

header := “”

for key, value := range Header {

header += key + “:” + value + “\r\n”

}

header += “\r\n”

buffer.WriteString(header)

return header

}

func (mail SendMail) writeFile(buffer *bytes.Buffer, fileName string) {

file, err := ioutil.ReadFile(fileName)

if err != nil {

panic(err.Error())

}

payload := make([]byte, base64.StdEncoding.EncodedLen(len(file)))

base64.StdEncoding.Encode(payload, file)

buffer.WriteString("\r\n")

for index, line := 0, len(payload); index < line; index++ {

buffer.WriteByte(payload[index])

if (index+1)%76 == 0 {

buffer.WriteString("\r\n")

}

}

}

func main() {

mail := &SendMail{user: “[email protected]”, password: “password”, host: “smtp.qq.com”, port: “25”}

message := Message{

from: “[email protected]”,

to: []string{“[email protected]”},

cc: []string{},

bcc: []string{},

subject: “test”, //郵件标題

body: “msg body!”, //正文内容

contentType: “text/plain;charset=utf-8”,

attachment: Attachment{

name: []string{“1.png”}, //可以放入多張圖檔

contentType: “image/png”,

withFile: true,

},

}

mail.Send(message)

}

下面再附上最終組合成的發送格式:

           

From:[email protected]

To:[email protected]

Cc:

Bcc:

Subject:test

Content-Type:multipart/related;boundary=GoBoundary

Date:2018-08-22 14:42:04.529271 +0800 CST m=+0.006003700

–GoBoundary

Content-Transfer-Encoding:base64

Content-Type:image/png;name=“1.png”

Content-ID: <1.png>

//圖檔base64編碼内容 太長就不顯示了

–GoBoundary

Content-Type: text/html; charset=UTF-8

<html>
	<body>
		<p>text:msg body!</p><br>
		<p><img src="cid:1.png" height=200 width=300></p><br>
					
	</body>
</html>
           

–GoBoundary–

----------
<br>
<font size=5>**總結**</font>

以上代碼可以實作在正文中添加多張圖檔的功能
當然隻要修改template 想怎麼發送就怎麼發送~~~

因為使用的是QQ郵箱 在password中填入QQ郵箱的授權碼
![這裡寫圖檔描述](https://img-blog.csdn.net/20180822154151834?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3prdDI4NjQ2ODU0MQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

這個方法是将圖檔按原先附件的方法添加
關鍵就是在之後的html中通過 <font color=red>**img src="cid:1.png"**</font>  來引用附件中的圖檔 進而在正文中顯示
![這裡寫圖檔描述](https://img-blog.csdn.net/20180822154233620?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3prdDI4NjQ2ODU0MQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)


這隻是我通過抓包發現的一種方法 總感覺有點麻煩
感覺應該存在其它更優的方法  希望能夠一起交流 謝謝!!