cradmin_email — Utilities for working with email

The purpose of this app is to make it easier to work with email, especially with HTML email.

Usage

Add django_cradmin.apps.cradmin_email to you INSTALLED_APPS-setting. See django_cradmin.apps.cradmin_email.emailutils.AbstractEmail for example usage.

Settings

DJANGO_CRADMIN_EMAIL_SUBJECT_PREFIX
Use this to specify a default prefix for email subjects send with django_cradmin.apps.cradmin_email.emailutils.AbstractEmail.
DJANGO_CRADMIN_EMAIL_DEFAULT_CONTEXT_DATA
Documented below.
DJANGO_CRADMIN_EMAIL_LOGO_HTML
HTML for the logo in HTML emails. Used by the default email header template. More documentation below.
DJANGO_CRADMIN_SITENAME
Use this to specify a site name that you can use in your email templates. Used by the default email header template.

HTML email formatting guide

HTML formatting in email is not like formatting in browsers. You actually need to forget more or less every good practice from the last 10 years of web development, and instead:

  • Use tables for layout (yes, TABLES for layout).
  • Avoid images. Many spam engines use the ratio between images and text, so do not use many images.
  • Set styles directly on elements.

Our solution

To make this easier to handle, we suggest the following:

  • For the actual content of your emails, use <br> to emulate paragraphs, and keep the formatting to the <a>, <strong>, <em> and <big> tags. For advanced formatting/layout, use <table>, but you should not need that if you use our template tags.
  • Use a common base template that styles the surrounding content for all your emails.

We make this easy to do by providing the cradmin_email/html_message_base.django.html template that you can extend in your html message templates:

  • You just have to override the contents block.
  • The template is styled via the DJANGO_CRADMIN_EMAIL_DEFAULT_CONTEXT_DATA setting.

Styling and tuning the html_message_base template

The easiest thing to adjust is the styles. You do this via the DJANGO_CRADMIN_EMAIL_DEFAULT_CONTEXT_DATA setting (a dict). You can set the following values:

body_style
The styles of the body element. Note that gmail ignores this.
outer_table_style
The CSS styles of the outer table.
common_td_style

Common styles for header, contents and footer. Make sure this ends with ;. Example:

font-family: Arial, sans-serif;
font-size: 16px;
line-height: 1.42857143;
letter-spacing: 0.5px;
padding-left: 10px;
padding-right: 10px;
header_td_style
The CSS styles of the header block. This is a <td> element.
contents_td_style
The CSS styles of the contents block. This is a <td> element.
footer_td_style
The CSS styles of the footer block. This is a <td> element.
link_style

This is not used by the base template, but you should use it on all the links you create to make it easy to style your links. Example:

<a href="http://example.com" style="{{ link_style }}">Go to example.com</a>
footer_link_style

This is not used by the base template, but you should use it on all the links you create in your footer template to make it easy to style your links. Example:

<a href="http://example.com" style="{{ footer_link_style }}">Go to example.com</a>
primary_button_link_style
Styles for the cradmin_email_primary_buttonlink() template tag.
secondary_button_link_style
Styles for the cradmin_email_secondary_buttonlink() template tag.
logo_style
Style for the logo. This is a <span> element. This element is rendered by the default header include template if you set the DJANGO_CRADMIN_EMAIL_LOGO_HTML setting.

Templates

cradmin_email/html_message_base.django.html
The base template for all HTML emails. You should not need to override this, but just extend it in all your email templates. How to style this template via DJANGO_CRADMIN_EMAIL_DEFAULT_CONTEXT_DATA is described above.
cradmin_email/include/html_message_header.django.html

Included cradmin_email/html_message_base.django.html to render the header. You can override this in one of your own apps - just ensure the app is listed before django_cradmin.apps.cradmin_email in INSTALLED_APPS.

The template should not need to be overridden if you can render your logo/header using HTML and CSS. You should instead adjust the logo_style, header_td_style and perhaps the header_td_style via the DJANGO_CRADMIN_EMAIL_DEFAULT_CONTEXT_DATA setting.

Design/develop/debug email rendering

To make it easy to visually develop the email template, we provide a view that you can add to your url config:

url(r'^cradmin_email/', include('django_cradmin.apps.cradmin_email.urls')),

And go to one of these URLs to debug email rendering:

Remember to test that your styles are responsive, and try to test with as many clients as possible. https://litmus.com/ is a good solution for this.

Template tags

Render a normal link.

Examples

Url as string:

{% load cradmin_email_tags %}
{% cradmin_email_link "http://example.com" %}
    A link
{% end_cradmin_email_link %}

Url as context variable:

{% load cradmin_email_tags %}
{% cradmin_email_link someurl %}
    A link
{% end_cradmin_email_link %}

Render a link as a primary button.

Examples

Url as string:

{% load cradmin_email_tags %}
{% cradmin_email_primary_buttonlink "http://example.com" %}
    A primary button link
{% end_cradmin_email_primary_buttonlink %}

Url as context variable:

{% load cradmin_email_tags %}
{% cradmin_email_primary_buttonlink someurl %}
    A primary button link
{% end_cradmin_email_primary_buttonlink %}

Render a link as a secondary button.

Examples

Url as string:

{% load cradmin_email_tags %}
{% cradmin_email_secondary_buttonlink "http://example.com" %}
    A secondary button link
{% end_cradmin_email_secondary_buttonlink %}

Url as context variable:

{% load cradmin_email_tags %}
{% cradmin_email_secondary_buttonlink someurl %}
    A secondary button link
{% end_cradmin_email_secondary_buttonlink %}

API

convert_html_to_plaintext(html)

Convert the given html to plain text.

class AbstractEmail(recipient=None, recipient_list=None, extra_context_data=None, from_email=None)

Bases: object

Abstract class for sending email.

Examples

Simple example:

from django_cradmin.apps.cradmin_email import emailutils

class SimpleEmail(emailutils.AbstractEmail):
    subject_template = 'myapp/subject.django.txt'
    html_message_template = 'myapp/html_message.django.html'

SimpleEmail(recipient='test@example.com').send()

Specify a sender:

SimpleEmail(recipient='test@example.com', from_email='admin@example.com').send()

Build a common abstract class that defaults to something other than settings.DEFAULT_FROM_EMAIL:

class AbstractAccountEmail(emailutils.AbstractEmail):
    def get_default_from_email(self):
        return 'account@example.com'

Specify a plaintext template instead of converting the HTML email to plaintext:

class WithPlaintextEmail(emailutils.AbstractEmail):
    subject_template = 'myapp/subject.django.txt'
    html_message_template = 'myapp/html_message.django.html'
    plaintext_message_template = 'myapp/plaintext_message.django.txt'

Set subject via a translation string instead of a template (you can do this for the message as well):

class StringSubjectEmail(emailutils.AbstractEmail):
    html_message_template = 'myapp/html_message.django.html'

    def render_subject(self):
        return _('My subject')

Provide context data for the templates:

SimpleEmail(recipient='test@example.com', extra_context_data={
    'name': 'Peter Pan',
}).send()
Parameters:
  • recipient (str) – The recipient of the email.
  • recipient_list (list) – The recipients of the email. Use this instead of recipient if you want to send the message to multiple people.
  • extra_context_data (dict) – An optional dict with extra context data for the templates.
  • from_email – The email address we send the message from. Defaults to get_default_from_email().
subject_template = None

The Django template for the subject. You must set this in subclasses, or override get_subject_template() or render_subject().

html_message_template = None

The Django template for the HTML message. You must set this in subclasses, or override get_html_message_template() or render_html_message().

plaintext_message_template = None

The Django template for the Plain text message. If this or get_plaintext_message_template() or render_subject() is not set in subclasses, we autoconvert the HTML message to plain text.

DEFAULT_CONTEXT_DATA = {'body_style': 'background-color: #fff;', 'contents_td_style': 'padding: 20px; ', 'primary_button_link_style': 'font-size: 16px; font-family: Arial, sans-serif; color: #fff; text-decoration: none; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; background-color: #377CA8; border-top: 10px solid #377CA8; border-bottom: 10px solid #377CA8; border-right: 16px solid #377CA8; border-left: 16px solid #377CA8; border-radius: 3px; -webkit-border-radius: 3px; -moz-border-radius: 3px; display: inline-block;', 'logo_style': 'font-size: 30px; font-weight: bold; padding: 0; ', 'link_style': 'color: #377CA8; text-decoration: underline;', 'secondary_button_link_style': 'font-size: 16px; font-family: Arial, sans-serif; color: #fff; text-decoration: none; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; background-color: #999999; border-top: 10px solid #999999; border-bottom: 10px solid #999999; border-right: 16px solid #999999; border-left: 16px solid #999999; border-radius: 3px; -webkit-border-radius: 3px; -moz-border-radius: 3px; display: inline-block;', 'header_td_style': 'padding: 20px; ', 'common_td_style': 'font-family: Arial, sans-serif; font-size: 16px; line-height: 1.42857143; margin: 0; letter-spacing: 0.5px; ', 'footer_td_style': 'padding-left: 20px; padding-right: 20px; color: #555; '}

Fallback value of the DJANGO_CRADMIN_EMAIL_DEFAULT_CONTEXT_DATA setting is not set.

get_subject_template()

Alternative way to specify subject_template. This takes presedence over subject_template.

get_html_message_template()

Alternative way to specify html_message_template. This takes presedence over html_message_template.

get_plaintext_message_template()

Alternative way to specify plaintext_message_template. This takes presedence over plaintext_message_template.

get_subject_prefix()

Get the prefix to use for the subject.

Defaults to settings.DJANGO_CRADMIN_EMAIL_SUBJECT_PREFIX, falling back to empty string.

If your privide a prefix, you should most likely include an empty space at the end of it.

render_subject()

Render the subject. You can override this if you want to adjust template rendering or avoid using a template.

render_html_message()

Render the html message. You can override this if you want to adjust template rendering or avoid using a template.

render_plaintext_message()

Render the plaintext message. You can override this if you want to adjust template rendering or avoid using a template.

If no plaintext_message_template or get_plaintext_message_template() is specified, we convert the HTML message to plaintext using convert_html_to_plaintext().

get_default_context_data()

Get the default context data.

You should normally not override this, but rather use it if you override get_context_data() and calling super().get_context_data() is not a suitable solution.

get_context_data()

Get the template context data sent to subject_template, html_message_template and plaintext_message_template.

By default this returns:

  • from_email.
  • DJANGO_CRADMIN_SITENAME (if set as a Django setting).
  • anything you send as the extra_context_data argument to the constructor.
  • Anything in the DJANGO_CRADMIN_EMAIL_DEFAULT_CONTEXT_DATA setting.
get_from_email()

Get the email address of the sender. Override this if you want to provide the from_email as a method instead of argument to the constructor.

get_recipient_list()

Get the list of recipients. Override this if you want to provide the recipient_list as a method instead of argument to the constructor.

get_send_mail_kwargs()

Get a dict with kwargs for django.core.mail.send_mail().

We default to building this from the various methods on this class, but you can override this to adjust the kwargs.

send()

Send the email.

get_default_from_email()

Get the fallback value for from_email. Defaults to settings.DEFAULT_FROM_EMAIL, but you can override this to provide a common superclass that defaults to sending from a different address.