Python email lib – How to remove attachment from existing message?

Question:

I have an email that I’m reading with the Python email lib that I need to modify the attachments of. The email Message class has the “attach” method, but does not have anything like “detach”. How can I remove an attachment from a multipart message? If possible, I want to do this without recreating the message from scratch.

Essentially I want to:

  1. Load the email
  2. Remove the mime attachments
  3. Add a new attachment
Asked By: john a macdonald

||

Answers:

Well, from my experience, in the context you are working, everything is a Message object. The message, its parts, attachments, everything. So, to accomplish what you want to do, you need to

  1. parse the message using the Parser API (this will get you the root Message object)
  2. Walk the structure, determining what you need and what you don’t (using a method of a Message instance, – .walk()), – remember, that everything is a Message.
  3. Attach whatever you need to attach to the parts you’ve extracted and you are good to go.

To reiterate, what you are working with is, essentially, a tree, where Message objects with .is_multipart() == True are nodes and Message objects with .is_multipart() == False are end-nodes (their payload is a string, not a bunch of Message objects).

Answered By: shylent

The way I’ve figured out to do it is:

  1. Set the payload to an empty list with set_payload
  2. Create the payload, and attach to the message.
Answered By: john a macdonald

set_payload() may help.

set_payload(payload[, charset])

Set the entire message object’s payload to payload. It is the client’s responsibility to ensure the payload invariants.

A quick interactive example:

>>> from email import mime,message
>>> m1 = message.Message()
>>> t1=email.MIMEText.MIMEText('t1rn')
>>> print t1.as_string()
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

t1

>>> m1.attach(t1)
>>> m1.is_multipart()
True
>>> m1.get_payload()
[<email.mime.text.MIMEText instance at 0x00F585A8>]
>>> t2=email.MIMEText.MIMEText('t2rn')
>>> m1.set_payload([t2])
>>> print m1.get_payload()[0].as_string()
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit

t2

>>> 
Answered By: gimel

For MIMEMultipart you can attach, but you can’t remove elements directly. Good news is that in this case get_payload() returns a standard python list of elements.

From https://docs.python.org/3/library/email.compat32-message.html

Return the current payload, which will be a list of Message objects when is_multipart() is True, or a string when is_multipart() is False. If the payload is a list and you mutate the list object, you modify the message’s payload in place.

To clear entire MIMEMultipart payload just assign new empty list:

multipart_related.set_payload([])

This example removes only selected items from multipart/related payload list:

  for part in email.walk():
    if part.get_content_type() == 'multipart/related':
      list_of_messages = part.get_payload()
      for message in list(list_of_messages):
        if message.get_content_type() != 'text/html' and message.get_content_type() != 'text/plain':
          list_of_messages.remove(part)
Answered By: mzmrk
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.