golang发送带附件的邮件
之前我写过 python邮件发送模块 ,里面有提到发送带附件的邮件,当时使用python自带的email 模块里已经封装好的包,直接引用即可。在golang下,原生的也有三个对应模块”mime”、”net/mail”、”net/smtp” ,不过这三个模块使用时,不能直接像python里那样简单的套用即可。golang下需要按照smtp协议的规范—RFC531 和MIME规范来生成相应的格式并发出去。
一、有关MIME规范
1、MIME规范
多用途互联网邮件扩展(MIME,Multipurpose Internet Mail Extensions)是一个互联网标准,它扩展了电子邮件标准,使其能够支持:
1非ASCII字符文本;
2非文本格式附件(二进制、声音、图像等);
3由多部分(multiple parts)组成的消息体;
4包含非ASCII字符的头信息(Header information)。
这个标准被定义在RFC 2045、RFC 2046、RFC 2047、RFC 2048、RFC 2049等RFC中。MIME改善了由RFC 822转变而来的RFC 2822,这些旧标准规定电子邮件标准并不允许在邮件消息中使用7位ASCII字符集以外的字符。正因如此,一些非英语字符消息和二进制文件,图像,声音等非文字消息原本都不能在电子邮件中传输(MIME可以)。MIME规定了用于表示各种各样的数据类型的符号化方法。此外,在万维网中使用的HTTP协议中也使用了MIME的框架,标准被扩展为互联网媒体类型。
2、带附件邮件发送格式
其发送格式如下:
1From:[email protected]
2To:[email protected]
3Subject:这是主题
4Mime-Version:1.0 //通常是1.0
5Content-Type:Multipart/mixed;Boundary="THIS_IS_BOUNDARY_JUST_MAKE_YOURS" //boundary为分界字符,跟http传文件时类似
6Date:当前时间
7--THIS_IS_BOUNDARY_JUST_MAKE_YOURS //boundary前边需要加上连接符 -- , 首部和第一个boundary之间有两个空行
8Content-Type:text/plain;chart-set=utf-8
9 //单个部分的首部和正文间有个空行
10这是正文1
11这是正文2
12--THIS_IS_BOUNDARY_JUST_MAKE_YOURS //每个部分的与上一部分之间一个空行
13Content-Type:image/jpg;name="test.jpg"
14Content-Transfer-Encoding:base64
15Content-Description:这个是描述
16 //单个部分的首部和正文间有个空行
17base64编码的文件 //文件内容使用base64 编码,单行不超过80字节,需要插入\r\n进行换行
18--THIS_IS_BOUNDARY_JUST_MAKE_YOURS-- //最后结束的标识--boundary--
具体也可以参看你自己foxmail 邮件中查看源代码的信息,如下图:
上图是我从一封邮件里提取了部分信息,有兴趣的可以自上而下看下全部信息。
格式书写时,需要注意以下几个问题:
11、头部写的boundary 在下边用的时候要拼上--前缀
22、含有附件的,第一个boundary 和 header 中间有两个空行
33、结束标记为 --boundary--
44、循环文件内容进行插入换行时,如果出现逻辑错误,则传输的附件显示异常,无法正常查看和下载。
二、golang实现
根据网上找到的代码,修改后的代码示例如下:
1package main
2import (
3 "bytes"
4 "encoding/base64"
5 "fmt"
6 "io/ioutil"
7 "net"
8 "net/smtp"
9 "strings"
10)
11const (
12 emlUser = "[email protected]"
13 emlPwd = "-------"
14 emlSMTP = "smtp.xxx.com:25"
15)
16func main() {
17 err := eml()
18 if err != nil {
19 fmt.Println(" err:", err)
20 }
21}
22// 发普通文本邮件
23func eml() error {
24 to := "[email protected]"
25 cc := "[email protected]"
26 sendTo := strings.Split(to, ";")
27 subject := "test mail for 361way.com"
28 boundary := "ds13difsknfsifuere134" //boundary 用于分割邮件内容,可自定义. 注意它的开始和结束格式
29 mime := bytes.NewBuffer(nil)
30 //设置邮件
31 mime.WriteString(fmt.Sprintf("From: %s\r\nTo: %s\r\nCC: %s\r\nSubject: %s\r\nMIME-Version: 1.0\r\n", emlUser, emlUser, to, cc, subject))
32 mime.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\r\n", boundary))
33 mime.WriteString("Content-Description: 这是一封带附档的邮件\r\n")
34 //邮件普通Text正文
35 mime.WriteString(fmt.Sprintf("--%s\r\n", boundary))
36 mime.WriteString("Content-Type: text/plain; charset=utf-8\r\n")
37 mime.WriteString("This is a multipart message in MIME format.")
38 // 第一个附件
39 attaFile := "/Users/xcl/xclcode/tconv.go"
40 attaFileName := "tconv.go"
41 mime.WriteString(fmt.Sprintf("\n--%s\r\n", boundary))
42 mime.WriteString("Content-Type: application/octet-stream\r\n")
43 mime.WriteString("Content-Description: 附一个Go文件\r\n")
44 mime.WriteString("Content-Transfer-Encoding: base64\r\n")
45 mime.WriteString("Content-Disposition: attachment; filename=\"" + attaFileName + "\"\r\n\r\n")
46 //读取并编码文件内容
47 attaData, err := ioutil.ReadFile(attaFile)
48 if err != nil {
49 return err
50 }
51 b := make([]byte, base64.StdEncoding.EncodedLen(len(attaData)))
52 base64.StdEncoding.Encode(b, attaData)
53 mime.Write(b)
54 //第二个附件
55 mime.WriteString(fmt.Sprintf("\r\n--%s\r\n", boundary))
56 mime.WriteString("Content-Type: text/plain\r\n")
57 mime.WriteString("Content-Description: 附一个Text文件\r\n")
58 mime.WriteString("Content-Disposition: attachment; filename=\"test.txt\"\r\n\r\n")
59 mime.WriteString("this is the attachment text") //这里写入的是附件test.txt的内容
60 //邮件结束
61 mime.WriteString("\r\n--" + boundary + "--\r\n\r\n")
62 fmt.Println(mime.String())
63 //发送相关
64 smtpHost, _, err := net.SplitHostPort(emlSMTP)
65 if err != nil {
66 return err
67 }
68 auth := smtp.PlainAuth("", emlUser, emlPwd, smtpHost)
69 return smtp.SendMail(emlSMTP, auth, emlUser, sendTo, mime.Bytes())
70}
三、第三方模块
虽然在golang的原生模块里是没有简洁方便的附件调用发送方法,但在很多第三方模块里都已经很好的进行了封装,这里列这个第三方模块,具体也可以参看下他们实现的方式。
https://github.com/scorredoira/email
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/golang-email-attachment/5856.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.