[Mailman-Developers] [Mailman-Users] handler to auto detach attachment and link it to a website keeping html

Mark Sapiro mark at msapiro.net
Fri Apr 18 22:30:51 CEST 2014


On 04/18/2014 09:48 AM, Sylvain Viart wrote:
> Coding question.
> 
> A bit of context:
> 
> Goal is to develop a custom handler to perform:
> 
>  * detach all attachments
>  * post detached content somewhere available on http
>  * modify the content of the original email, keeping original html,
>    adding an html link to the moved document
>  * adding a small clip image as an attachment symbol as an embed object
> 
> 
> Le 16/04/2014 16:01, Mark Sapiro a écrit :
>> <https://docs.python.org/2/library/email.mime.html> to create new
>> sub-parts and use the Message.attach() method to attach them. 
> 
> 
> How can I replace the part which contain the html part, by a new one
> which will become :
> 
> 
>>> Content-Type: multipart/related
>>>>>Content-Type: text/html;
>>>>> Content-Type: image/png; name="clip-24.png"
> 
> The text/html is the old one.
>
> Adding a part is ok, but replacing it with a new one which embed the
> previous one… I dont see.
> 
> part of the code I've produced:
> 
>     if msg.is_multipart():
>         syslog('debug', 'multipart message rewriting')
>         related = None
> 
>         for part in msg.walk():
>             ctype = part.get_content_type()
>             if ctype == 'text/plain' and not part['X-Mailman-Part']:
>                 new_footer = txt_attacht_replace + footer_attach
>                 part.set_payload(part.get_payload() + new_footer)
>                 continue
> 
>             elif ctype == 'text/html':
>                 related = MIMEMultipart('related')

This stuff ----------------
>                 clip = MIMEText(attach_clip)
>                 clip.add_header('Content-Disposition', 'inline')
>                 clip.add_header('Content-ID', '<part1.%d>' % 123412)
>                 clip['Content-Transfer-Encoding'] = 'base64'
>                 del clip['Content-type']
>                 del clip['Content-transfer-encoding']
>                 clip['Content-type'] = 'image/png;
> name="attachment-24.png"'
>                 clip['Content-transfer-encoding'] = 'base64'
should be ---------------

                clip = MIMEImage(xxx, 'png')

where xxx is the actual png data, e.g.
    xxx = open('some_file.png').read()


>                 html_footer = html_attachment_holder %
> {'html_attachment_clip_tpl': html_footer_attach}
>                 html_footer += '</body>'
>                 old_content = part.get_payload()
>                 new_content = re.sub(r'</body>', html_footer, old_content)
>                 part.set_payload(new_content)
>
>                 related.attach(part)
>                 related.attach(clip)


Now related is the part you want. all that remains is to replace the
original part with related
> 
>                 # WRONG
>                 del part
>                 msg.attach(related)


Correct. That's wrong.  You need to do this differently. You need to
walk the message, but with your own code rather than msg.walk so you can
build your new message as you go.

You need some variant of

from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage

def fix_msg(msg):
    if msg.is_multipart():
        parts = msg.get_payload()
        # remove the next level parts, then process and reattach them
        msg.set_payload(None)
        for p in parts:
            msg.attach(fix_msg(p))
        return msg
    else:
        # process the 'leaf' parts
        ctype = msg.get_content_type()
        if ctype == 'text/plain' and not part['X-Mailman-Part']:
            # add footer to plain text
            new_footer = txt_attacht_replace + footer_attach
            msg.set_payload(part.get_payload() + new_footer)
            return msg
        elif ctype == 'text/html':
            # build multipart/related for HTML
            related = MIMEMultipart('related')
            clip = MIMEImage(xxx, 'png')
            html_footer = html_attachment_holder %
{'html_attachment_clip_tpl': html_footer_attach}
            html_footer += '</body>'
            old_content = msg.get_payload()
            new_content = re.sub(r'</body>', html_footer, old_content)
            msg.set_payload(new_content)
            related.attach(msg)
            related.attach(clip)
            return related

def process(mlist, msg, msgdata)
    ...
    msg = fix_msg(msg)
    ...

-- 
Mark Sapiro <mark at msapiro.net>        The highway is for gamblers,
San Francisco Bay Area, California    better use your sense - B. Dylan


More information about the Mailman-Developers mailing list