Opened 17 years ago

Closed 16 years ago

#4771 closed (wontfix)

EmailHTML - EmailMessage with HTML and related/inline images support

Reported by: sime <simon@…> Owned by: nobody
Component: Core (Mail) Version: dev
Severity: Keywords: EmailMessage multipart mail html attachments Content-ID
Cc: nick.lane.au@… Triage Stage: Design decision needed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Seems we need the ability to specify Content-Type 'name' header for attachments, when using the new mail objects. I'm trying to send an HTML mail with images, using EmailMultiAlternatives, attach_alternative, and attach_file, but the resulting message isn't readable. It's attaching everything OK, but not with the right headers.

Change History (4)

comment:1 by nick.lane.au@…, 17 years ago

I haven't looked into this yet, but you might need to use the Content-ID header for the image.
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/473810

comment:2 by sime <simon@…>, 17 years ago

Cc: nick.lane.au@… added
Summary: EmailMultiAlternatives doesn't support named image/media attachmentsEmailHTML - EmailMessage with HTML and related/inline images support
Triage Stage: UnreviewedDesign decision needed

Here is a derivative of EmailMessage that allows nice easy HTML with inline images. It also provides a multipart/related-safe way of attaching HTML and automatically fixes file references in your HTML to point to inline attachments.

class EmailHTML(EmailMessage):
    multipart_subtype = 'related'
    html = None
    related_ids = []
    
    def message(self):
        if self.html:
            for id in self.related_ids:
                self.html = self.html.replace(id, 'cid:' + id)
            encoding = self.encoding or settings.DEFAULT_CHARSET
            ha = SafeMIMEText(self.html, 'html', encoding)
            if self.body:
                a = SafeMIMEMultipart(_subtype='alternative')
                a.attach(SafeMIMEText(smart_str(self.body, encoding), self.content_subtype, encoding))
                a.attach(ha)
            else:
                a = ha
            self.attachments.insert(0, a)
            self.body = None
            self.html = None
        return super(EmailHTML, self).message()
        
    def attach_html(self, html):
        """
        Specify HTML to include in the message.
        """
        self.html = html
                    
    def attach_related(self, path, mimetype=None):
        """
        Attaches a file from the filesystem, with a Content-ID.
        For use with multipart/related messages.
        """
        filename = os.path.basename(path)
        content = open(path, 'rb').read()
        self.attachments.append((filename, content, mimetype, True))
        self.related_ids += [ filename ]

    def _create_attachment(self, filename, content, mimetype=None, with_id=False):
        """
        Convert the filename, content, mimetype triple into a MIME attachment
        object. Adjust headers to use Content-ID where applicable.
        """
        attachment = super(EmailHTML, self)._create_attachment(filename, content, mimetype)
        if filename and with_id:
            # change headers to suit
            del(attachment['Content-Disposition'])
            mimetype = attachment['Content-Type']
            del(attachment['Content-Type'])
            attachment.add_header('Content-Type', mimetype, name=filename)
            attachment.add_header('Content-ID', '<%s>' % filename)
        return attachment

comment:3 by simo <simon@…>, 17 years ago

If we're including multipart and attachment support in core.mail, then I think this (or similar) should be included also.

See also ticket #4781 a typo fix required to make this class work.

comment:4 by Jacob, 16 years ago

Resolution: wontfix
Status: newclosed

I think this doesn't make much sense as a built-in: HTML email is so weird that pretty much everyone wants to do things differently (my HTMLEmail class is similar to the above, but different in a few ways). Since there really isn't a one-size-fits-all (or even a one-size-fits-most) solution, I'm going to close this wontfix.

Note: See TracTickets for help on using tickets.
Back to Top