附件名称中的 Unicode 字符

Unicode Characters in Attachment name

我正在尝试编写一个程序,使用 SMTP 将 PDF 发送到我的 Kindle。

当我使用常规客户端(即 Outlook)向 Kindle 发送附件时,我得到了正确的文件名,即使它是 non-ASCII。但是,当我使用代码发送它时,Unicode 字符显示不正确。我试着把附件发到我的个人邮箱,里面没有任何问题,只是Kindle不认识字符。

这是我的附件headers:


Content-Disposition: attachment; filename="Ø§ÙØ¶Ø­Ù ÙØ§ÙÙØ³ÙاÙ.pdf"

Content-Transfer-Encoding: base64

Content-Type: application/pdf; name="Ø§ÙØ¶Ø­Ù ÙØ§ÙÙØ³ÙاÙ.pdf"

这是我的代码:

package main

import (
    "log"

    "gopkg.in/gomail.v2"
)

func main() {
    m := gomail.NewMessage()

    m.SetHeader("To", "MY-KINDLE-EMAIL@kindle.com")
    m.SetHeader("From", "MY-EMAIL@hotmail.com")
    m.SetBody("text/plain", "")

    path := "C:\Users\al111\Downloads\Telegram Desktop\كيف تعمل الماركسية.pdf"
    m.Attach(path)
    d := gomail.NewDialer("smtp.live.com", 587, "MY-EMAIL@hotmail.com", "MY-PASSWORD")

    err := d.DialAndSend(m)
    if err != nil {
        log.Fatal(err)
    }
}

RFC 2822 style email headers do not allow unescaped Unicode characters. You need to use an ASCII-compatible encoding, such as RFC20471 or RFC 2231,例如:

Content-Disposition: attachment;
  filename="=?UTF-8?Q?=D9=83=D9=8A=D9=81=20=D8=AA=D8=B9=D9=85=D9=84=20=D8=A7=D9=84=D9=85=D8=A7=D8=B1=D9=83=D8=B3=D9=8A=D8=A9=2E=70=64=66.pdf?="

Content-Type: application/pdf;
  name="=?UTF-8?Q?=D9=83=D9=8A=D9=81=20=D8=AA=D8=B9=D9=85=D9=84=20=D8=A7=D9=84=D9=85=D8=A7=D8=B1=D9=83=D8=B3=D9=8A=D8=A9=2E=70=64=66.pdf?="
Content-Disposition: attachment;
  filename*=UTF-8''%D9%83%D9%8A%D9%81%20%D8%AA%D8%B9%D9%85%D9%84%20%D8%A7%D9%84%D9%85%D8%A7%D8%B1%D9%83%D8%B3%D9%8A%D8%A9%2E%70%64%66.pdf

Content-Type: application/pdf;
  name*=UTF-8''%D9%83%D9%8A%D9%81%20%D8%AA%D8%B9%D9%85%D9%84%20%D8%A7%D9%84%D9%85%D8%A7%D8%B1%D9%83%D8%B3%D9%8A%D8%A9%2E%70%64%66.pdf

1:是的,我知道 RFC 2047 技术上 不允许 quoted-strings 中的 encoded-word,例如参数值。但是许多服务器确实允许这样做。

参见:

How to encode the filename parameter value of the Content-Disposition header in MIME message?

The mess that is attachment filenames

很可能 Outlook 在向您发送电子邮件时正是这样做的。您可以通过查看它实际发送的电子邮件的原始数据来验证。

在 Go 中,m.Attach() 函数有一个可选的 settings 参数,可用于为附件传递附加参数,例如自定义文件名甚至自定义 headers,例如:

baseName := mime.QEncoding.Encode("utf-8", filepath.Base(path))
m.Attach(path, gomail.Rename(baseName))
baseName := url.PathEscape(filepath.Base(path))
m.Attach(path, gomail.SetHeader(map[string][]string{
        "Content-Disposition": {"attachment; filename*=UTF-8''" + baseName},
    }))