Is msg.is_attachment() enough to get all the attachments from email in python, or should we check that msg.is_multipart() too?

I am searching for mails from a particular sender with a particular subject. I take the first email, and then want to retrieve the attachments from it.

I'm using imaplib.

My code -

_, mails = imap_client.search(None, f'(FROM "{sender}")', f'(SUBJECT "{subject}")')
first_mail = mails[0].split()[0]
mail_msgs = [email.message_from_bytes(response[1]) for response in first_mail if isinstance(response, tuple)]
msg = mail_msgs[0]
attachments = [part for part in msg.walk() if msg.is_multipart() and part.get_content_disposition() == "attachment"]

My question is regarding the last line - to retrieve the attachments, do i need to check if the msg is both is_multipart() and get_content_disposition()

attachments = [part for part in msg.walk() if msg.is_multipart() and part.get_content_disposition() == "attachment"]

or will only checking for get_content_disposition() suffice?

attachments = [part for part in msg.walk() if part.get_content_disposition() == "attachment"]
    

Solution 1:

Possible bug

email.message_from_bytes() is not guaranteed to return an email.message.EmailMessage object. It returns an email.message.Message object, which does not necessarily have the is_attachment() method. So you might want to pass _class=email.message.EmailMessage to email.message_from_bytes().

Answer to the question

Message.is_multipart() checks whether the message is a multipart message. This does not mean, that it contains an attachment file. It will also match emails, which are sent with dual text/html and text/plain bodies. If you want to filter multipart messages, this is all you need. If you want to filter file attachments, you want to filter using part.is_attachment() on the messages parts. In the latter case, is_attachment() is sufficient.