|
from __future__ import absolute_import |
|
import os.path |
|
import re |
|
|
|
from email.MIMEBase import MIMEBase |
|
|
|
from django.conf import settings |
|
from django.core.mail import EmailMultiAlternatives, SafeMIMEMultipart |
|
|
|
class EmailMultiRelated(EmailMultiAlternatives): |
|
""" |
|
A version of EmailMessage that makes it easy to send multipart/related |
|
messages. For example, including text and HTML versions with inline images. |
|
|
|
@see https://djangosnippets.org/snippets/2215/ |
|
""" |
|
related_subtype = 'related' |
|
|
|
def __init__(self, *args, **kwargs): |
|
# self.related_ids = [] |
|
self.related_attachments = [] |
|
return super(EmailMultiRelated, self).__init__(*args, **kwargs) |
|
|
|
def attach_related(self, filename=None, content=None, mimetype=None): |
|
""" |
|
Attaches a file with the given filename and content. The filename can |
|
be omitted and the mimetype is guessed, if not provided. |
|
|
|
If the first parameter is a MIMEBase subclass it is inserted directly |
|
into the resulting message attachments. |
|
""" |
|
if isinstance(filename, MIMEBase): |
|
assert content == mimetype == None |
|
self.related_attachments.append(filename) |
|
else: |
|
assert content is not None |
|
self.related_attachments.append((filename, content, mimetype)) |
|
|
|
def attach_related_file(self, path, mimetype=None): |
|
"""Attaches a file from the filesystem.""" |
|
filename = os.path.basename(path) |
|
content = open(path, 'rb').read() |
|
self.attach_related(filename, content, mimetype) |
|
|
|
def _create_message(self, msg): |
|
return self._create_attachments(self._create_related_attachments(self._create_alternatives(msg))) |
|
|
|
def _create_alternatives(self, msg): |
|
for i, (content, mimetype) in enumerate(self.alternatives): |
|
if mimetype == 'text/html': |
|
for related_attachment in self.related_attachments: |
|
if isinstance(related_attachment, MIMEBase): |
|
content_id = related_attachment.get('Content-ID') |
|
content = re.sub(r'(?<!cid:)%s' % re.escape(content_id), 'cid:%s' % content_id, content) |
|
else: |
|
filename, _, _ = related_attachment |
|
content = re.sub(r'(?<!cid:)%s' % re.escape(filename), 'cid:%s' % filename, content) |
|
self.alternatives[i] = (content, mimetype) |
|
|
|
return super(EmailMultiRelated, self)._create_alternatives(msg) |
|
|
|
def _create_related_attachments(self, msg): |
|
encoding = self.encoding or settings.DEFAULT_CHARSET |
|
if self.related_attachments: |
|
body_msg = msg |
|
msg = SafeMIMEMultipart(_subtype=self.related_subtype, encoding=encoding) |
|
if self.body: |
|
msg.attach(body_msg) |
|
for related_attachment in self.related_attachments: |
|
if isinstance(related_attachment, MIMEBase): |
|
msg.attach(related_attachment) |
|
else: |
|
msg.attach(self._create_related_attachment(*related_attachment)) |
|
return msg |
|
|
|
def _create_related_attachment(self, filename, content, mimetype=None): |
|
""" |
|
Convert the filename, content, mimetype triple into a MIME attachment |
|
object. Adjust headers to use Content-ID where applicable. |
|
Taken from http://code.djangoproject.com/ticket/4771 |
|
""" |
|
attachment = super(EmailMultiRelated, self)._create_attachment(filename, content, mimetype) |
|
if filename: |
|
mimetype = attachment['Content-Type'] |
|
del(attachment['Content-Type']) |
|
del(attachment['Content-Disposition']) |
|
attachment.add_header('Content-Disposition', 'inline', filename=filename) |
|
attachment.add_header('Content-Type', mimetype, name=filename) |
|
attachment.add_header('Content-ID', '<%s>' % filename) |
|
return attachment |