Skip to content

Instantly share code, notes, and snippets.

@SmileyChris
Last active March 5, 2016 08:49
Show Gist options
  • Save SmileyChris/5881290 to your computer and use it in GitHub Desktop.
Save SmileyChris/5881290 to your computer and use it in GitHub Desktop.
Handle template-base email messages in Django
from email.Utils import formataddr
import os
from django.conf import settings
from django.core import mail
from django import template
from django.template.loader import select_template, get_template
def template_email(template_name, extra_context=None, *args, **kwargs):
"""
Return an :cls:`~django.core.mail.EmailMessage` with the body (and
optionally, the subject) set from django templates.
:param template_name: The template name, or partial template name.
:param extra_context: A dictionary of context data to pass to the email
templates.
Passing the full template name will render the email body using this
template. If the template extension is ``htm`` or ``html``, the message
mime subtype will be changed to ``html``. For example::
message = template_email(
template_name='emails/alert.txt', subject="Alert!",
to=['bob@example.com'])
message.send()
Passing a partial template allows a plain text body, an HTML alternative,
and the subject to all be templates. For example, calling
``template_email(template_name='emails/welcome')`` will look for the
following templates:
* ``emails/welcome_subject.txt`` will set the message's subject line. Only
the first non-blank line of this file will be used.
* ``emails/welcome.txt`` will be the plain text body.
* ``emails/welcome.html`` will be the HTML alternative if a plain text body
is also found, otherwise it'll be the body and the message mime subtype
will be changed to ``html``.
If neither the plain text or HTML template exist, a
:cls:`~django.template.TemplateDoesNotExist` exception will be raised. The
subject template is optional.
The subject and plain text body templates are rendered with auto-escape
turned off.
"""
message = mail.EmailMultiAlternatives(*args, **kwargs)
context = template.Context(extra_context)
html_template_names = ['{}.html'.format(template_name)]
txt_template_names = ['{}.txt'.format(template_name)]
if os.path.splitext(template_name)[1].lower() in ('.htm', '.html'):
html_template_names.append(template_name)
else:
txt_template_names.append(template_name)
# Get the HTML body.
try:
html = select_template(html_template_names).render(context)
except template.TemplateDoesNotExist:
html = None
# The remainder of the templates are text only, so turn off autoescaping.
context.autoescape = False
# Get the plain-text body.
try:
txt = select_template(txt_template_names).render(context)
except template.TemplateDoesNotExist:
if not html:
# Neither body template exists.
raise
txt = None
# Get the subject.
try:
subject = (
get_template('{}_subject.txt'.format(template_name))
.render(context)
)
message.subject = subject.strip().splitlines()[0]
except template.TemplateDoesNotExist:
pass
if txt:
message.body = txt
if html:
message.attach_alternative(html, 'text/html')
else:
message.content_subtype = 'html'
message.body = html
return message
def template_mail_managers(**kwargs):
return _template_email_convenience(to=settings.MANAGERS, **kwargs)
def template_mail_admins(**kwargs):
return _template_email_convenience(to=settings.ADMINS, **kwargs)
def _template_email_convenience(to, fail_silently=False, **kwargs):
to = [formataddr(recipient) for recipient in to]
final_kwargs = {'from_email': settings.SERVER_EMAIL}
final_kwargs.update(kwargs)
message = template_email(to=to, **final_kwargs)
if settings.EMAIL_SUBJECT_PREFIX:
message.subject = (
settings.EMAIL_SUBJECT_PREFIX + message.subject)
message.send(fail_silently=fail_silently)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment