在Python3.x中解码邮件主题Thunderbird

在Python3.x中解码邮件主题Thunderbird,python,python-3.x,email,unicode,thunderbird,Python,Python 3.x,Email,Unicode,Thunderbird,有关解决方法,请参见下文 /原始问题: 对不起,我实在太笨了,无法独自解决这个问题。我正试图从雷鸟的.mbox文件夹中读取几封电子邮件中的“主题”。现在,我正在尝试使用decode\u header()对头进行解码,但仍然会出现错误 我正在使用以下功能(我相信有一种更聪明的方法可以做到这一点,但这不是本文的重点) 前100个左右的输出完全正常,但随后出现以下错误消息: ----------------------------------------------------------------

有关解决方法,请参见下文

/原始问题:

对不起,我实在太笨了,无法独自解决这个问题。我正试图从雷鸟的.mbox文件夹中读取几封电子邮件中的“主题”。现在,我正在尝试使用
decode\u header()
对头进行解码,但仍然会出现错误

我正在使用以下功能(我相信有一种更聪明的方法可以做到这一点,但这不是本文的重点)

前100个左右的输出完全正常,但随后出现以下错误消息:

---------------------------------------------------------------------------
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-97-e252df04c215> in <module>
----> 1 for message in mflder:
      2     try:
      3         print(header_to_string(message["subject"]))
      4     except:
      5         print("0")

~\anaconda3\lib\mailbox.py in itervalues(self)
    107         for key in self.iterkeys():
    108             try:
--> 109                 value = self[key]
    110             except KeyError:
    111                 continue

~\anaconda3\lib\mailbox.py in __getitem__(self, key)
     71         """Return the keyed message; raise KeyError if it doesn't exist."""
     72         if not self._factory:
---> 73             return self.get_message(key)
     74         else:
     75             with contextlib.closing(self.get_file(key)) as file:

~\anaconda3\lib\mailbox.py in get_message(self, key)
    779         string = self._file.read(stop - self._file.tell())
    780         msg = self._message_factory(string.replace(linesep, b'\n'))
--> 781         msg.set_from(from_line[5:].decode('ascii'))
    782         return msg
    783 

UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 4: ordinal not in range(128)
。。。只需使用:

for x in range(len(mflder)):
    try:
        message = mflder[x]
        print(header_to_string(message["subject"]))
    except:
        print("Failed loading message!")

这将跳过.mbox文件夹中的断开邮件。然而,在处理.mbox文件夹主题时,我偶然发现了几个其他问题。例如,在使用
decode\u header()
函数时,有时会将头拆分为几个元组。因此,为了接收完整的主题,还需要向
header\u to\u string()
函数添加更多内容。但这与这个问题无关了。我是一个noob和一个爱好编程的人,但我记得我使用outlookapi和Python,这更容易…

解决方案 您可能损坏了“mailfolder”mbox文件,或者Python的
邮箱
模块中存在由文件中的某些内容触发的错误。如果没有mbox输入文件或复制问题的最小示例输入文件,我就无法判断发生了什么

你可以自己调试一下。文件中的每条消息都以“发件人”行开头,该行应如下所示:

From-Mon-Mar 30 18:18:04 2020
从您发布的堆栈跟踪来看,其中一条消息中该行的格式似乎不正确。就我个人而言,我会使用IDE调试器(PyCharm)来跟踪格式错误的行是什么,但这可以通过Python内置的
pdb
来完成。像这样包装您的循环:

导入pdb
尝试:
对于mFolder中的消息:
打印(标题到字符串(消息[“主题”]))
除:
pdb.验尸报告()
当您现在运行代码时,当异常发生时,它将进入调试器。在该提示下,您可以输入
l
,列出调试器停止的代码;这应该与最初发布的堆栈跟踪中打印的最后一帧匹配。到达后,有两个命令将告诉您发生了什么:

p from_line
将显示格式错误的“发件人”行

将显示
邮箱
代码认为邮件应该在文件中的偏移量

以前的答案没有解决原来的问题,但仍然适用 在现实世界中,会有不符合标准的消息。如果您不想拒绝错误消息,可以尝试使代码更宽容。使用“latin-1”解码是处理这些带有ASCII以外字节的报头的一种方法。这不能失败,因为所有可能的字节值都映射到有效的Unicode字符(Unicode与ISO/IEC 8859-1的前256个代码的一对一映射,也称为“拉丁-1”)。这可能会也可能不会给您发送人想要的文本

导入邮箱
从email.header导入解码\u头
mflder=mailbox.mbox(“邮件文件夹”)
def get_主题(消息):
标题=消息[“主题”]
如果不是标题:
返回“”
头,编码=解码头(头)[0]
如果编码不是无:
尝试:
头=头。解码(编码)
除:
header=header.decode('latin-1')
回流集管
对于mFolder中的消息:
打印(获取主题(消息))

谢谢你的想法!但这并不能解决问题。从错误消息中可以看出,问题发生在迭代mailboxfolder时。这似乎是
get_message()
方法的一个问题,该方法尝试将某些内容解码为“ascii”,而显然不是“ascii”。我不知道如何解决这个问题。。。有没有一种方法可以组合一个
try。。除了
循环的块之外?多亏了corona,我现在无法测试它,因为我的孩子们快把我逼疯了。^^我更新了我的答案,以表明您的问题与mbox文件中格式错误的“发件人”行有关。如果您可以更新您的问题,使其包含重现问题的示例mbox文件,或者在错误发生时至少包含调试信息,如
from\u line
的值,我们可能能够找到根本原因。好的,非常感谢您的帮助!我将对此进行测试,否则只需尝试找出导致这些问题的邮件,将其删除,然后重试。好的,我更新了我的初始帖子,因为我找到了解决方法。问题是直接迭代.mbox文件夹,这会导致邮件中断问题。
for x in range(len(mflder)):
    try:
        message = mflder[x]
        print(header_to_string(message["subject"]))
    except:
        print("Failed loading message!")

p from_line
p start