发送带PDF附件的SMTP邮件是否必须使用Base64编码?
SMTP发送带PDF附件的邮件:是否必须Base64编码?
我想发送一封带PDF附件的邮件,找到一个可用的Golang示例,运行正常,但我觉得Base64编码没必要,就省略了该步骤并修改了邮件头,新的BuildMail函数如下:
func BuildMail(mail Mail) []byte { var buf bytes.Buffer buf.WriteString(fmt.Sprintf("From: %s\r\n", mail.Sender)) buf.WriteString(fmt.Sprintf("To: %s\r\n", strings.Join(mail.To, ";"))) buf.WriteString(fmt.Sprintf("Subject: %s\r\n", mail.Subject)) boundary := "my-boundary-779" buf.WriteString("MIME-Version: 1.0\r\n") buf.WriteString(fmt.Sprintf("Content-Type: multipart/mixed; boundary=%s\n", boundary)) buf.WriteString(fmt.Sprintf("\r\n--%s\r\n", boundary)) buf.WriteString("Content-Type: text/plain; charset=\"utf-8\"\r\n") buf.WriteString(fmt.Sprintf("\r\n%s", mail.Body)) buf.WriteString(fmt.Sprintf("\r\n--%s\r\n", boundary)) buf.WriteString("Content-Type: application/pdf\r\n") buf.WriteString("Content-Disposition: attachment; filename=words.pdf\r\n") buf.WriteString("Content-ID: <words.pdf>\r\n\r\n") data := readFile("words.pdf") buf.Write(data) buf.WriteString(fmt.Sprintf("\r\n--%s", boundary)) buf.WriteString("--") return buf.Bytes() }
但运行后收到的PDF附件是空的,请问通过SMTP发送邮件时,附件是否必须进行Base64编码?原因是什么?
回答
是的,二进制附件(比如PDF)必须进行Base64编码,核心原因有两个:
SMTP协议的文本传输限制:SMTP本质是基于ASCII文本的协议,只能安全传输0-127范围内的字符。PDF这类二进制文件包含大量128-255的非ASCII字节,直接发送会被SMTP服务器识别为非法字符,要么被截断、篡改,要么直接丢弃,导致接收端拿到空附件或损坏文件。
MIME规范的强制要求:MIME(多用途互联网邮件扩展)明确规定,对于
application/pdf这类二进制内容,必须通过Content-Transfer-Encoding头声明编码方式,并使用Base64将二进制数据转换为ASCII兼容格式。Base64会把3字节二进制数据转成4个ASCII字符,完美适配SMTP的文本传输规则,保证数据完整无损。
你省略编码后,邮件客户端无法解析乱码的二进制数据,自然会显示附件为空。修复方法很直接:
- 给PDF附件的头部加上
Content-Transfer-Encoding: base64 - 用Go标准库的
encoding/base64包把读取到的PDF数据编码后再写入缓冲区
修改后的附件段代码示例:
buf.WriteString(fmt.Sprintf("\r\n--%s\r\n", boundary)) buf.WriteString("Content-Type: application/pdf\r\n") buf.WriteString("Content-Disposition: attachment; filename=words.pdf\r\n") buf.WriteString("Content-ID: <words.pdf>\r\n") buf.WriteString("Content-Transfer-Encoding: base64\r\n\r\n") data := readFile("words.pdf") encoder := base64.NewEncoder(base64.StdEncoding, &buf) encoder.Write(data) encoder.Close() buf.WriteString(fmt.Sprintf("\r\n--%s", boundary))
这样就能确保PDF附件被正确传输和解析了。
内容的提问来源于stack exchange,提问作者Frank
相关产品推荐
相关产品推荐

