【问题标题】:Decoding Mail Subject Thunderbird in Python 3.x在 Python 3.x 中解码邮件主题 Thunderbird
【发布时间】:2020-07-11 07:02:21
【问题描述】:

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

/原问题:

对不起,我太笨了,无法自己解决这个问题。我正在尝试从 Thunderbird 的 .mbox 文件夹中存储的几封电子邮件中读取“主题”。现在,我正在尝试使用 decode_header() 解码标头,但我仍然收到 UnicodeErrors。

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

import mailbox
from email.header import decode_header

mflder = mailbox.mbox("mailfolder")

for message in mflder:
    print(header_to_string(message["subject"]))

def header_to_string(header):
    try:
        header, encoding = decode_header(header)[0]
    except:
        return "something went wrong {}".format(header)
    if encoding == None:
        return header
    else:
        return header.decode(encoding)

前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)

如何强制mailbox.py 解码不同的编码?还是标题只是坏了?如果我理解正确,标题应该是“ASCII”,对吧?我的意思是,这就是整个 MIME 事情的重点,不是吗?

感谢您的帮助!

/解决方法

我通过避免直接迭代 .mbox 邮件文件夹表示找到了一种解决方法。而不是使用 ...

for message in mflder:
    # do something

...只需使用:

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

这会跳过 .mbox 文件夹中的损坏邮件。然而,在使用 .mbox 文件夹主题时,我偶然发现了其他几个问题。例如,使用decode_header() 函数时,有时会将标头拆分为几个元组。因此,为了接收完整的主题,还需要向header_to_string() 函数添加更多内容。但这不再与这个问题有关。我是一个菜鸟和业余爱好者,但我记得使用 Outlook API 和 Python,这要容易得多...

【问题讨论】:

  • 我更新了我的答案,表明您的问题与 mbox 文件中格式错误的“发件人”行有关。如果您可以更新您的问题以包含重现问题的示例 mbox 文件,或者至少在错误发生时调试信息(例如 from_line 的值),我们或许能够找到根本原因。
  • 好的,非常感谢您的帮助!我将对此进行测试,否则只需尝试找出导致这些问题的邮件,将其删除,然后重试。
  • 好的,我更新了我的初始帖子,因为我找到了解决方法。问题是直接遍历 .mbox 文件夹,这会导致消息损坏。

标签: python python-3.x email unicode thunderbird


【解决方案1】:

解决方案

您的“邮件文件夹”mbox 文件似乎已损坏,或者您的文件中的某些内容触发了 Python 的 mailbox 模块中的错误。如果没有 mbox 输入文件或重现问题的最小示例输入文件,我无法判断发生了什么。

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

From - Mon Mar 30 18:18:04 2020

从您发布的堆栈跟踪来看,该行在其中一条消息中的格式似乎有误。就个人而言,我会使用 IDE 调试器 (PyCharm) 来跟踪格式错误的行是什么,但可以使用 Python 的内置 pdb 来完成。像这样包装你的循环:

import pdb
try:
    for message in mflder:
        print(header_to_string(message["subject"]))
except:
    pdb.post_mortem()

当您现在运行代码时,它会在异常发生时放入调试器。在该提示符下,您可以输入l 以列出调试器停止的代码;这应该与您最初发布的堆栈跟踪中打印的最后一帧相匹配。一旦你在那里,有两个命令会告诉你发生了什么:

p from_line

将向您显示格式错误的“发件人”行。

p start

将向您显示mailbox 代码认为消息应该在文件中的哪个偏移量。

以前的答案没有解决原始问题但仍然适用

在现实世界中,会有不符合标准的消息。如果您不想拒绝坏消息,可以尝试使代码更宽容。使用“latin-1”解码是处理这些带有 ASCII 以外字节的标头的一种方法。这不会失败,因为所有可能的字节值都映射到有效的 Unicode 字符(Unicode 的前 256 个代码与 ISO/IEC 8859-1,又名“latin-1”的一对一映射)。这可能会或可能不会给您发件人想要的文本。

import mailbox
from email.header import decode_header

mflder = mailbox.mbox("mailfolder")

def get_subject(message):
    header = message["subject"]
    if not header:
        return ''
    header, encoding = decode_header(header)[0]
    if encoding is not None:
        try:
            header = header.decode(encoding)
        except:
            header = header.decode('latin-1')
    return header

for message in mflder:
    print(get_subject(message))

【讨论】:

  • 感谢您的想法!但这并不能解决问题。从错误消息中可以看出,在遍历邮箱文件夹时会出现问题。 get_message() 方法似乎有问题,它试图将某些东西解码为“ascii”,而这显然不是“ascii”。我不知道如何解决这个问题......有没有办法将try .. except 块与for 循环结合起来?多亏了电晕,我现在无法测试它,因为我的孩子快把我逼疯了。^^
猜你喜欢
  • 2015-05-12
  • 1970-01-01
  • 2015-02-06
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
  • 2011-04-27
  • 2017-05-16
  • 2011-11-26
相关资源
最近更新 更多