email_from_template generates and sends mail defined in Django templates to avoid presentation layer violations. It has the following features:
- HTML email support
- Context processor system
- Support for non-Django template rendering systems
Whilst Django provides a comprehensive mail framework that simplifies the sending mechanics of email, the typical use of it is often ugly and results in unnecessary and complicated string formatting inside views:
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.contrib.sites.models import Site
# Shouldn't be in views.py
send_mail(
'Hi %s, %d %s written on your wall' % (
user.username,
num_posts > 1 and 'people have' or 'person has',
),
'Hi %s\n\nCheck out what they wrote here:\n\n %s%s\n\n' % (
user.username,
Site.objects.get_current(),url,
reverse('profile:view', args=(user.username,)),
),
'from@example.com',
[user.email],
fail_silently=False,
)
With django-email-from-template, you can relegate all this formatting to the presentation layer as well as leverage any existing templatetags and filters. First we define our template:
{% extends email_from_template %}
{% block subject %}
Hi {{ user.username }}, {{ num_posts }} {{ num_posts|pluralize:"person has,people have" }} written on your wall
{% endblock %}
{% block body %}
Hi {{ user.username }}.
Check out what they wrote here:
{{ site.url }}{% url profile:view user.username %}
{% endblock %}
We then simply call our template-aware version of send_mail with the appropriate context:
from email_from_template import send_mail
send_mail([user.email], 'path/to/my_email.email', {
'user': user,
'num_posts': num_posts,
}, 'from@email.com')
Now your views are not cluttered with unnecessary presentation logic.
For HTML-enabled mail readers, we can optionally include suitable content within a “html” block:
{% block html %}
<p>Hi <strong>{{ user.username }}</strong></p>
<p>Check out what they wrote here:</p>
<a href="{{ site.url }}{% url profile:view user.username %}">
{{ site.url }}{% url profile:view user.username %}
</a>
{% endblock %}
The EMAIL_CONTEXT_PROCESSORS setting is a tuple of callables that return a dictionary of items to merged into the email context. It is identical to the functionality of Django’s regular TEMPLATE_CONTEXT_PROCESSORS support except that the callables do not take a request object.
By default, EMAIL_CONTEXT_PROCESSORS is set to:
(
'email_from_template.context_processors.debug',
'email_from_template.context_processors.django_settings',
)
Module: email_from_template.context_processors.debug Enabled by default: True
Sets debug in the template context to the value of settings.DEBUG:
def debug():
from django.conf import settings
return {'debug': settings.DEBUG}
Module: email_from_template.context_processors.django_settings Enabled by default: True
Sets settings in the template context to the value of Django’s settings object, django.conf.settings:
def django_settings():
from django.conf import settings
return {'settings': settings}
Module: email_from_template.context_processors.site Enabled by default: False
Sets site in the template context to the value of the current django.contrib.sites Site instance:
def site():
from django.contrib.sites.models import Site
return {'site': Site.objects.get_current()}
Module: email_from_template.context_processors.i18n Enabled by default: False
Includes LANGUAGES, LANGUAGE_CODE and LANGUAGE_BIDI in the template context. This email context processor is parallel to the django.core.context_processors.i18n template context processor:
def i18n():
from django.utils import translation
return {
'LANGUAGES': settings.LANGUAGES,
'LANGUAGE_CODE': translation.get_language(),
'LANGUAGE_BIDI': translation.get_language_bidi(),
}
A tuple of callables that return a dictionary of items to merged into the email context. See the Context processors section for more details.
Add email_from_template to your INSTALLED_APPS:
INSTALLED_APPS = (
...
'email_from_template',
...
)