如何获取 UTF-8 格式的电子邮件?

How to get Email in UTF-8?

我正在做一个 Python 脚本来接收人们通过我的电子邮件地址发送的邮件。

我正在使用 ImapClient 模块,我得到了电子邮件的内容,但原型很奇怪,我所有的 UTF-8 字符都是编码的,如下所示:

No=C3=ABl

这是我的一段代码:

    email_message = email.message_from_bytes(message_data[b'RFC822'])
    print(email_message.get_payload(0))

我也尝试在我的 get_payload 中添加 decode=True 参数,但它 returns 我 NoneType.

您必须首先确定您感兴趣的电子邮件部分。然后,您将根据该部分的编码解码该部分的内容。每个部分可能有不同的编码 and/or 字符集。如果您对电子邮件的主体感兴趣,这通常是第一部分,可以是 html,也可以是纯文本,具体取决于发送它的程序(某些用户代理,如 gmail,将包括两种形式)。

您可以在邮件对象上使用电子邮件模块的 EmailMessage.walk() 功能来查看各种附件及其各自的内容类型。这些部分用一个特殊的 "boundary" 字符串(通常是随机的)相互分隔,该字符串不会出现在消息正文中(以避免歧义)。让电子邮件模块为您处理部件更容易——尤其是因为部件可以嵌套。

您在问题中显示的文本片段似乎是经过可引用打印编码的。您可以在此处找到从 quoted-printable 到 utf-8 的示例转换:Change "Quoted-printable" encoding to "utf-8"

一个例子:

我在下面添加了一个示例模拟原始消息,它将代表构成 EmailMessage 对象的字节。在一封电子邮件中,每个 section/part(主体、附件等)都可以有不同的内容类型、字符集和传输编码。部分可以嵌入子部分,但电子邮件消息通常只有一个平面结构。对于作为附件的部分,找到内容配置值也很常见,该值指示文件内容的建议文件名。

Subject: Woah
From: "Sébastien" <seb@example.org>
To: Bob <bob@example.org>
Content-Type: multipart/alternative; boundary="000000000000690fec05765c6a66"

--000000000000690fec05765c6a66
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

S=C3=A9bastien est un pr=C3=A9nom.

--000000000000690fec05765c6a66
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div di=
r=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"lt=
r"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr"><div=
dir=3D"ltr"><div dir=3D"ltr"><div dir=3D"ltr">...

...

一旦您 select 感兴趣的部分,您必须使用该部分的编码设置来正确转换有效负载。您将首先撤消任何传输编码(例如 quoted-printable),然后根据字符集解码结果字符串。

如果您想要的部分的字符集已经是 UTF-8,那么您所要做的就是撤消内容传输编码(例如,删除引用的可打印序列)。但是,如果该部分的字符集不同,比如 Latin-1,您将不得不从字节转到 unicode,然后从 unicode 返回到 utf8:

# remove quoted-printable encoding
unquoted = quopri.decodestring(mime_part_payload)

# latin-1 in this case is the charset of the mime part header
tmp_unicode = unquoted.decode('latin-1', errors='ignore')

# encode to desired encoding
u8 = tmp_unicode.encode('utf-8')