使用 python email 通过电子邮件发送带有非 ascii 文件名的附件

Suz*_*ana 5 python email unicode character-encoding rfc2231

如何发送附有文件名包含 unicode 字符的电子邮件?

到目前为止,文件将到达,但文件名为“noname”

这部分非常适合 ASCII 文件名:

import smtplib
from email.mime.text import MIMEText
from email.MIMEBase import MIMEBase
from email.MIMEMultipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.Utils import formatdate
from email import Encoders
from email.Utils import encode_rfc2231

msg = MIMEMultipart()
msg['Subject'] = "New magazine delivery!"
msg['From'] = sender_email
msg['To'] = ', '.join(kindle_emails)
msg['Date'] = formatdate(localtime=True)
message = "see attachment"
msg.attach(MIMEText(message))
part = MIMEApplication(open(f, 'rb').read(), _subtype='application/x-mobipocket-ebook')

part.add_header('Content-Disposition', 'attachment', filename=os.path.basename(filename)
msg.attach(part)
Run Code Online (Sandbox Code Playgroud)

第一次尝试

添加编码、语言和编码字符串的元组,而不仅仅是文件名。

part.add_header('Content-Disposition', 'attachment', filename=('utf-8', 'fr', os.path.basename(f).encode('utf-8')))
Run Code Online (Sandbox Code Playgroud)

第二次尝试:

像这样设置全局字符集:

from email import Charset
Charset.add_charset('utf-8', Charset.QP, Charset.QP, 'utf-8')
Run Code Online (Sandbox Code Playgroud)

第三次尝试

使用utils.encode_rfc2231

from email.Utils import encode_rfc2231
utf8filename = encode_rfc2231(os.path.basename(f).encode('utf-8'), charset='utf-8')
part.add_header('Content-Disposition', 'attachment', filename=('utf-8', 'fr', utf8filename))
Run Code Online (Sandbox Code Playgroud)

第四次尝试

用于urllib.quote()对文件名进行 urlencode。这对文件名具有与第三种方法相同的效果。

utf8filename = urllib.quote(os.path.basename(f).encode('utf-8'))
part.add_header('Content-Disposition', 'attachment', filename=('utf-8', 'fr', utf8filename))
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

我是否遗漏了 RFC2231 文件名字符编码的一些重要内容?

我使用 Gmail 的 SMTP 服务器和 python 2.7。

Suz*_*ana 4

而不是像这样告诉服务器它是 UTF-8:

filename=('utf-8', 'fr', os.path.basename(f).encode('utf-8'))
Run Code Online (Sandbox Code Playgroud)

...当我在没有告知的情况下发送 UTF-8 时它就起作用了:

filename=os.path.basename(f).encode('utf-8')
Run Code Online (Sandbox Code Playgroud)

文件名将正确显示。

这似乎与文档中所述的内容相矛盾:

如果值包含非 ASCII 字符,则必须将其指定为格式为 (CHARSET, LANGUAGE, VALUE) 的三元组,其中 CHARSET 是命名用于对值进行编码的字符集的字符串,LANGUAGE 通常可以设置为None 或空字符串(有关其他可能性,请参阅 RFC 2231),VALUE 是包含非 ASCII 代码点的字符串值。

这不起作用,但是python 3 文档添加了: 。

如果未传递三元组并且该值包含非 ASCII 字符,则会使用 utf-8 的 CHARSET 和 None 的 LANGUAGE 自动以 RFC 2231 格式对其进行编码。

即使对于 python 2.7,只有这个有效,尽管文档中没有提到。