鉴于Python 2.6中的RFC822消息,我如何获得正确的文本/纯文本内容部分?基本上,我想要的算法是:
message = email.message_from_string(raw_message)
if has_mime_part(message, "text/plain"):
mime_part = get_mime_part(message, "text/plain")
text_content = decode_mime_part(mime_part)
elif has_mime_part(message, "text/html"):
mime_part = get_mime_part(message, "text/html")
html = decode_mime_part(mime_part)
text_content = render_html_to_plaintext(html)
else:
# fallback
text_content = str(message)
return text_content
在这些事情中,我有get_mime_part
和has_mime_part
,但我不太确定如何从MIME部分获取解码后的文本。我可以使用get_payload()
获取编码的文本,但如果我尝试使用decode
方法的get_payload()
参数(请参阅the doc)我当我在text / plain部分调用它时出错:
File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/ email/message.py", line 189, in get_payload raise TypeError('Expected list, got %s' % type(self._payload)) TypeError: Expected list, got <type 'str'>
此外,我不知道如何使用HTML并尽可能地将其呈现为文本。
答案 0 :(得分:80)
在多部分电子邮件中,email.message.Message.get_payload()
会返回一个列表,其中包含每个部分的一个项目。最简单的方法是遍历消息并获取每个部分的有效负载:
import email
msg = email.message_from_string(raw_message)
for part in msg.walk():
# each part is a either non-multipart, or another multipart message
# that contains further parts... Message is organized like a tree
if part.get_content_type() == 'text/plain':
print part.get_payload() # prints the raw text
对于非多部分消息,无需进行所有步行。无论content_type如何,您都可以直接使用get_payload()。
msg = email.message_from_string(raw_message)
msg.get_payload()
如果内容是编码的,则需要将None
作为第一个参数传递给get_payload()
,然后是True(解码标志是第二个参数)。例如,假设我的电子邮件包含MS Word文档附件:
msg = email.message_from_string(raw_message)
for part in msg.walk():
if part.get_content_type() == 'application/msword':
name = part.get_param('name') or 'MyDoc.doc'
f = open(name, 'wb')
f.write(part.get_payload(None, True)) # You need None as the first param
# because part.is_multipart()
# is False
f.close()
至于获得HTML部分的合理纯文本近似,我发现html2text的效果非常好。
答案 1 :(得分:1)
Flat比嵌套更好;)
from email.mime.multipart import MIMEMultipart
assert isinstance(msg, MIMEMultipart)
for _ in [k.get_payload() for k in msg.walk() if k.get_content_type() == 'text/plain']:
print _
答案 2 :(得分:0)
要添加@Jarret Hardie的出色答案:
我个人喜欢将这种数据结构转换为以后可以重用的字典,因此类似这样的情况,其中content_type
是键,而payload
是值:
import email
[...]
email_message = {
part.get_content_type(): part.get_payload()
for part in email.message_from_bytes(raw_email).walk()
}
print(email_message["text/plain"])