AttributeError: "NoneType" object has no attribute 'decode'

AttributeError: "NoneType" object has no attribute 'decode'

我正在 Python3 中尝试从我的 gmail 收件箱中阅读一封电子邮件。所以我遵循了本教程:https://www.thepythoncode.com/article/reading-emails-in-python

我的代码如下:

 username = "*****@gmail.com"
password = "******"
# create an IMAP4 class with SSL 
imap = imaplib.IMAP4_SSL("imap.gmail.com")
# authenticate
imap.login(username, password)
status, messages = imap.select("INBOX")
# total number of emails
messages = int(messages[0])
    

for i in range(messages, 0, -1):
    # fetch the email message by ID
    res, msg = imap.fetch(str(i), "(RFC822)")
    for response in msg:
        if isinstance(response, tuple):
            # parse a bytes email into a message object
            msg = email.message_from_bytes(response[1])
            # decode the email subject
            subject = decode_header(msg["Subject"])[0][0]
            if isinstance(subject, bytes):
                # if it's a bytes, decode to str
                subject = subject.decode()
            # email sender
            from_ = msg.get("From")
            # if the email message is multipart
            if msg.is_multipart():
                # iterate over email parts
                for part in msg.walk():
                    # extract content type of email
                    content_type = part.get_content_type()
                    content_disposition = str(part.get("Content-Disposition"))

                    # get the email body
                    body = part.get_payload(decode=True).decode()
                    print(str(body))

    imap.close()
    imap.logout()
    print('DONE READING EMAIL')

我使用的库是:

import imaplib
import email
from email.header import decode_header

但是,当我执行它时,我收到以下错误消息,我不明白,因为我的收件箱中从来没有空电子邮件...

Traceback (most recent call last):

  File "<ipython-input-19-69bcfd2188c6>", line 38, in <module>
    body = part.get_payload(decode=True).decode()

AttributeError: 'NoneType' object has no attribute 'decode'

有人知道我的问题是什么吗?

来自documentation:

Optional decode is a flag indicating whether the payload should be decoded or not, according to the Content-Transfer-Encoding header. When True and the message is not a multipart, the payload will be decoded if this header’s value is quoted-printable or base64. If some other encoding is used, or Content-Transfer-Encoding header is missing, or if the payload has bogus base64 data, the payload is returned as-is (undecoded). If the message is a multipart and the decode flag is True, then None is returned. The default for decode is False.

(注意:此 link 用于 python2 - 无论出于何种原因,python3 的相应页面似乎并未提及 get_payload。)

所以这听起来像是某条消息的一部分:

  • 缺少内容传输编码(email.message 没有说明它是如何解码的),或者
  • 正在使用 QP 或 base64 以外的编码(email.message 不支持解码),或
  • 声称是 base-64 编码但包含无法解码的错误编码字符串

最好的办法可能就是跳过它。

替换:

                    body = part.get_payload(decode=True).decode()

与:

                    payload = part.get_payload(decode=True)
                    if payload is None:
                        continue
                    body = payload.decode()

尽管我不确定您在 payload 上调用的 decode() 方法是否在做任何有用的事情,除了 get_payload 在使用 [=19] 时已经完成的解码之外=].您可能应该对此进行测试,如果您发现对 decode 的调用没有执行任何操作(即如果 bodypayload 相等),那么您可能会完全省略此步骤:

                    body = part.get_payload(decode=True)
                    if body is None:
                        continue

如果您添加一些关于 from_subject 的打印语句,您应该能够识别受影响的邮件,然后转到 gmail 中的“显示原始”进行比较,看看到底发生了什么。

高级 imap 库可能对这里有帮助:

from imap_tools import MailBox

# get emails from INBOX folder
with MailBox('imap.mail.com').login('test@mail.com', 'pwd', 'INBOX') as mailbox:
    for msg in mailbox.fetch():
        msg.uid              # str or None: '123'
        msg.subject          # str: 'some subject 你 привет'
        msg.from_            # str: 'sender@ya.ru'
        msg.to               # tuple: ('iam@goo.ru', 'friend@ya.ru', )
        msg.cc               # tuple: ('cc@mail.ru', )
        msg.bcc              # tuple: ('bcc@mail.ru', )
        msg.reply_to         # tuple: ('reply_to@mail.ru', )
        msg.date             # datetime.datetime: 1900-1-1 for unparsed, may be naive or with tzinfo
        msg.date_str         # str: original date - 'Tue, 03 Jan 2017 22:26:59 +0500'
        msg.text             # str: 'Hello 你 Привет'
        msg.html             # str: '<b>Hello 你 Привет</b>'
        msg.flags            # tuple: ('SEEN', 'FLAGGED', 'ENCRYPTED')
        msg.headers          # dict: {'Received': ('from 1.m.ru', 'from 2.m.ru'), 'AntiVirus': ('Clean',)}

        for att in msg.attachments:  # list: [Attachment]
            att.filename         # str: 'cat.jpg'
            att.content_type     # str: 'image/jpeg'
            att.payload          # bytes: b'\xff\xd8\xff\xe0\'

https://github.com/ikvk/imap_tools