Opened 8 years ago

Closed 7 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: master
Severity: Keywords: EmailMessage multipart mail html attachments Content-ID
Cc:… Triage Stage: Design decision needed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:


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 Changed 8 years ago by…

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

I haven't looked into this yet, but you might need to use the Content-ID header for the image.

comment:2 Changed 8 years ago by sime <simon@…>

  • Cc… added
  • Summary changed from EmailMultiAlternatives doesn't support named image/media attachments to EmailHTML - EmailMessage with HTML and related/inline images support
  • Triage Stage changed from Unreviewed to Design 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 = 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
            mimetype = attachment['Content-Type']
            attachment.add_header('Content-Type', mimetype, name=filename)
            attachment.add_header('Content-ID', '<%s>' % filename)
        return attachment

comment:3 Changed 8 years ago by simo <simon@…>

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 Changed 7 years ago by jacob

  • Resolution set to wontfix
  • Status changed from new to closed

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