Email 从mbox文件中提取电子邮件正文,将其解码为纯文本,而不考虑字符集和内容传输编码
我试图使用Python 3从thunderbird mbox文件中提取电子邮件正文。这是一个IMAP帐户 我希望电子邮件正文的文本部分可以作为unicode字符串处理。它应该“看起来”像Thunderbird中的电子邮件,并且不包含转义字符,如\r\n=20等 我认为这是我不知道如何解码或删除的内容传输编码。 我收到各种不同内容类型和不同内容传输编码的电子邮件。 这是我目前的尝试:Email 从mbox文件中提取电子邮件正文,将其解码为纯文本,而不考虑字符集和内容传输编码,email,python-3.x,content-type,plaintext,mbox,Email,Python 3.x,Content Type,Plaintext,Mbox,我试图使用Python 3从thunderbird mbox文件中提取电子邮件正文。这是一个IMAP帐户 我希望电子邮件正文的文本部分可以作为unicode字符串处理。它应该“看起来”像Thunderbird中的电子邮件,并且不包含转义字符,如\r\n=20等 我认为这是我不知道如何解码或删除的内容传输编码。 我收到各种不同内容类型和不同内容传输编码的电子邮件。 这是我目前的尝试: import mailbox import quopri,base64 def myconvert(encode
import mailbox
import quopri,base64
def myconvert(encoded,ContentTransferEncoding):
if ContentTransferEncoding == 'quoted-printable':
result = quopri.decodestring(encoded)
elif ContentTransferEncoding == 'base64':
result = base64.b64decode(encoded)
mboxfile = 'C:/Users/Username/Documents/Thunderbird/Data/profile/ImapMail/server.name/INBOX'
for msg in mailbox.mbox(mboxfile):
if msg.is_multipart(): #Walk through the parts of the email to find the text body.
for part in msg.walk():
if part.is_multipart(): # If part is multipart, walk through the subparts.
for subpart in part.walk():
if subpart.get_content_type() == 'text/plain':
body = subpart.get_payload() # Get the subpart payload (i.e the message body)
for k,v in subpart.items():
if k == 'Content-Transfer-Encoding':
cte = v # Keep the Content Transfer Encoding
elif subpart.get_content_type() == 'text/plain':
body = part.get_payload() # part isn't multipart Get the payload
for k,v in part.items():
if k == 'Content-Transfer-Encoding':
cte = v # Keep the Content Transfer Encoding
print(body)
print('Body is of type:',type(body))
body = myconvert(body,cte)
print(body)
但这在以下方面失败:
Body is of type: <class 'str'>
Traceback (most recent call last):
File "C:/Users/David/Documents/Python/test2.py", line 31, in <module>
body = myconvert(body,cte)
File "C:/Users/David/Documents/Python/test2.py", line 6, in myconvert
result = quopri.decodestring(encoded)
File "C:\Python32\lib\quopri.py", line 164, in decodestring
return a2b_qp(s, header=header)
TypeError: 'str' does not support the buffer interface
正文的类型为:
回溯(最近一次呼叫最后一次):
文件“C:/Users/David/Documents/Python/test2.py”,第31行,在
body=myconvert(body,cte)
myconvert中第6行的文件“C:/Users/David/Documents/Python/test2.py”
结果=量化解码字符串(编码)
文件“C:\Python32\lib\quopri.py”,第164行,解码字符串
返回a2b_qp(s,页眉=页眉)
TypeError:“str”不支持缓冲区接口
以下是一些执行此任务的代码,它打印错误,而不是在失败的消息中崩溃。我希望它可能有用。请注意,如果Python3中有一个bug,并且该bug已经修复,那么lines.get_payload(decode=True)可能会返回一个str对象,而不是bytes对象。我今天在2.7.2和Python 3.2.1上运行了这段代码
import mailbox
def getcharsets(msg):
charsets = set({})
for c in msg.get_charsets():
if c is not None:
charsets.update([c])
return charsets
def handleerror(errmsg, emailmsg,cs):
print()
print(errmsg)
print("This error occurred while decoding with ",cs," charset.")
print("These charsets were found in the one email.",getcharsets(emailmsg))
print("This is the subject:",emailmsg['subject'])
print("This is the sender:",emailmsg['From'])
def getbodyfromemail(msg):
body = None
#Walk through the parts of the email to find the text body.
if msg.is_multipart():
for part in msg.walk():
# If part is multipart, walk through the subparts.
if part.is_multipart():
for subpart in part.walk():
if subpart.get_content_type() == 'text/plain':
# Get the subpart payload (i.e the message body)
body = subpart.get_payload(decode=True)
#charset = subpart.get_charset()
# Part isn't multipart so get the email body
elif part.get_content_type() == 'text/plain':
body = part.get_payload(decode=True)
#charset = part.get_charset()
# If this isn't a multi-part message then get the payload (i.e the message body)
elif msg.get_content_type() == 'text/plain':
body = msg.get_payload(decode=True)
# No checking done to match the charset with the correct part.
for charset in getcharsets(msg):
try:
body = body.decode(charset)
except UnicodeDecodeError:
handleerror("UnicodeDecodeError: encountered.",msg,charset)
except AttributeError:
handleerror("AttributeError: encountered" ,msg,charset)
return body
#mboxfile = 'C:/Users/Username/Documents/Thunderbird/Data/profile/ImapMail/server.name/INBOX'
print(mboxfile)
for thisemail in mailbox.mbox(mboxfile):
body = getbodyfromemail(thisemail)
print(body[0:1000])
此脚本似乎正确返回了所有消息:
def getcharsets(msg):
charsets = set({})
for c in msg.get_charsets():
if c is not None:
charsets.update([c])
return charsets
def getBody(msg):
while msg.is_multipart():
msg=msg.get_payload()[0]
t=msg.get_payload(decode=True)
for charset in getcharsets(msg):
t=t.decode(charset)
return t
acd以前的回答通常只返回真实消息的一些页脚。
(
至少在我为这个工具箱打开的GMANE电子邮件中:
)
干杯真奇怪。get_payload()应该返回字节,但是Python 3下的str应该返回字节,除非您传入
decode=True
,而您没有传入。我刚刚用decode=True尝试过,它确实返回字节,因此没有错误。看起来解码已经完成了,现在我需要做的就是将字节转换成字符串。虽然我还没有用多种内容编码的电子邮件测试过这一点。哈,这似乎是个bug,但应该是相反的,decode=True应该返回str,decode=False字节。:-)知道这一点很有帮助,谢谢。我意识到我在这个问题上花了很多时间,因为我没有花足够的时间理解一些基本知识。现在看来,我需要获取字符集,然后使用body.decode(字符集)。这似乎适用于大多数电子邮件,但在一些电子邮件中,我得到了AttributeError:我认为这是由于电子邮件中的字符来自另一个字符集。我发现了以下信息:大多数非多部分类型的消息被解析为具有字符串负载的单个消息对象。对于is_multipart(),这些对象将返回False。他们的get_payload()方法将返回一个string对象。所有多部分类型的消息都将被解析为一个容器消息对象,其有效负载包含一系列子消息对象。对于is_multipart(),外部容器消息将返回True,其get_payload()方法将返回消息子部分的列表。从…起