I am trying to read an email from my gmail inbox in Python3. So I followed this tutorial : https://www.thepythoncode.com/article/reading-emails-in-python
My code is the following :
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')
The libraries I am using is :
import imaplib
import email
from email.header import decode_header
However, when I execute it I get the following error message, which I don't understand because I never have an empty email in my inbox ...
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'
Anyone has an idea what my problem could be ?
From the 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.
(Note: this link is for python2 - for whatever reason the corresponding page for python3 doesn't seem to mention get_payload
.)
So it sounds like either some part of some message:
email.message
no indication how it is meant to be decoded), oremail.message
does not support decoding it), orThe best thing to do is probably just to skip over it.
Replace:
body = part.get_payload(decode=True).decode()
with:
payload = part.get_payload(decode=True)
if payload is None:
continue
body = payload.decode()
Although I am not sure whether the decode()
method that you are calling on the payload
is doing anything useful beyond the decoding that get_payload
has already done when using decode=True
. You should probably test this, and if you find that this call to decode
does not do anything (i.e. if body
and payload
are equal), then you would probably omit this step entirely:
body = part.get_payload(decode=True)
if body is None:
continue
If you add some print statements regarding from_
and subject
, you should be able to identify the affected message(s), and then go to "show original" in gmail to compare, and see exactly what is going on.