Title: AttributeError in email.message.iter_attachments()
Type: behavior Stage: patch review
Components: email Versions: Python 3.8
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: barry, r.david.murray, skrohlas, stoksc
Priority: normal Keywords: patch

Created on 2018-06-26 14:43 by skrohlas, last changed 2018-07-11 07:56 by serhiy.storchaka.

Pull Requests
URL Status Linked Edit
PR 8041 closed python-dev, 2018-07-02 05:35
Messages (2)
msg320494 - (view) Author: Sven Krohlas (skrohlas) Date: 2018-06-26 14:43
Hello everyone,

Today I stumbled over unexpected behaviour when parsing emails with Python 3.5.

mail is of type: <class 'email.message.EmailMessage'>

Traceback (most recent call last):
File "XXX", line YYY, in ZZZ
for attachment in mail.iter_attachments():
File "/usr/lib/python3.5/email/", line 1025, in iter_attachments
parts = self.get_payload().copy()
AttributeError: 'str' object has no attribute 'copy'

/usr/lib/python3.5/email/ calls self.get_payload().copy() without distinguishing between different possible return types of get_payload().

get_payload() belongs to class MIMEPart(Message)

From the (base) class Message:

"def get_payload(self, i=None, decode=False):
"""Return a reference to the payload.

The payload will either be a list object or a string."

So, it might return a string, which seems to be the case I'm hitting here.

The code in cpython trunk still looks identical apart from a few line offsets, so newer versions might be affected, too.

Am I doing something wrong or do we have a bug to squash here?

msg320852 - (view) Author: stoksc (stoksc) * Date: 2018-07-02 05:39
Hey Sven,

New here, decided to try a bit at an issue. 

According to the email.message docs, "the payload is either a string or bytes object, in the case of simple message objects, or a list of EmailMessage objects, for MIME container documents such as multipart/* and message/rfc822 message objects."

Like you said, this error happens if the email.message.EmailMessage object is bad, i.e. the payload is a string or bytes but the content-type is marked as multipart/*. After reading online, it seems like an error is necessary.

I've proposed a small change in a pull request to make this situation raise a more useful error. It doesn't blow up any earlier but it at least says something more useful. 

The function could return instead of throwing an error, just providing an empty iterator, but that seems even less useful.

I fixed it on master (3.8 dev or whatever).

Date User Action Args
2018-07-11 07:56:34serhiy.storchakasettype: crash -> behavior
2018-07-02 05:39:42stokscsetnosy: + stoksc

messages: + msg320852
versions: + Python 3.8, - Python 3.5
2018-07-02 05:35:21python-devsetkeywords: + patch
stage: patch review
pull_requests: + pull_request7650
2018-06-26 14:43:31skrohlascreate