簡體   English   中英

在 Python 3.x 中解碼郵件主題 Thunderbird

[英]Decoding Mail Subject Thunderbird in Python 3.x

有關解決方法,請參見下文

/原問題:

對不起,我太笨了,無法自己解決這個問題。 我正在嘗試從 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,這要容易得多......

解決方案

看起來您的“mailfolder”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

將向您顯示格式錯誤的“From”行。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM