Django module to easily send templated emails using django templates, or using a transactional mail provider (mailchimp, silverpop, etc.)

Overview

Django-Templated-Email

GitterBadge PypiversionBadge PythonVersionsBadge LicenseBadge

Info: A Django oriented templated email sending class
Author: Bradley Whittington (http://github.com/bradwhittington, http://twitter.com/darb)
Tests: TravisBadge CoverageBadge

Overview

django-templated-email is oriented towards sending templated emails. The library supports template inheritance, adding cc'd and bcc'd recipients, configurable template naming and location.

The send_templated_email method can be thought of as the render_to_response shortcut for email.

Make sure you are reading the correct documentation:

develop branch: https://github.com/vintasoftware/django-templated-email/blob/develop/README.rst

stable pypi/master: https://github.com/vintasoftware/django-templated-email/blob/master/README.rst

Requirements

  • Python (3.6, 3.7, 3.8, 3.9)
  • Django (2.2, 3.1, 3.2)

We highly recommend and only officially support the latest patch release of each Python and Django series.

Getting going - installation

Installing:

pip install django-templated-email

You can add the following to your settings.py (but it works out the box):

TEMPLATED_EMAIL_BACKEND = 'templated_email.backends.vanilla_django.TemplateBackend'

# You can use a shortcut version
TEMPLATED_EMAIL_BACKEND = 'templated_email.backends.vanilla_django'

# You can also use a class directly
from templated_email.backends.vanilla_django import TemplateBackend
TEMPLATED_EMAIL_BACKEND = TemplateBackend

Sending templated emails

Example usage using vanilla_django TemplateBackend backend

Python to send mail:

from templated_email import send_templated_mail
send_templated_mail(
        template_name='welcome',
        from_email='[email protected]',
        recipient_list=['[email protected]'],
        context={
            'username':request.user.username,
            'full_name':request.user.get_full_name(),
            'signup_date':request.user.date_joined
        },
        # Optional:
        # cc=['[email protected]'],
        # bcc=['[email protected]'],
        # headers={'My-Custom-Header':'Custom Value'},
        # template_prefix="my_emails/",
        # template_suffix="email",
)

If you would like finer control on sending the email, you can use get_templated_email, which will return a django EmailMessage object, prepared using the vanilla_django backend:

from templated_email import get_templated_mail
get_templated_mail(
        template_name='welcome',
        from_email='[email protected]',
        to=['[email protected]'],
        context={
            'username':request.user.username,
            'full_name':request.user.get_full_name(),
            'signup_date':request.user.date_joined
        },
        # Optional:
        # cc=['[email protected]'],
        # bcc=['[email protected]'],
        # headers={'My-Custom-Header':'Custom Value'},
        # template_prefix="my_emails/",
        # template_suffix="email",
)

You can also cc and bcc recipients using cc=['[email protected]'].

Your template

The templated_email/ directory needs to be the templates directory.

The backend will look in my_app/templates/templated_email/welcome.email :

{% block subject %}My subject for {{username}}{% endblock %}
{% block plain %}
  Hi {{full_name}},

  You just signed up for my website, using:
      username: {{username}}
      join date: {{signup_date}}

  Thanks, you rock!
{% endblock %}

If you want to include an HTML part to your emails, simply use the 'html' block :

{% block html %}
  <p>Hi {{full_name}},</p>

  <p>You just signed up for my website, using:
      <dl>
        <dt>username</dt><dd>{{username}}</dd>
        <dt>join date</dt><dd>{{signup_date}}</dd>
      </dl>
  </p>

  <p>Thanks, you rock!</p>
{% endblock %}

The plain part can also be calculated from the HTML using html2text. If you don't specify the plain block and html2text package is installed, the plain part will be calculated from the HTML part. You can disable this behaviour in settings.py :

TEMPLATED_EMAIL_AUTO_PLAIN = False

You can also specify a custom function that converts from HTML to the plain part :

def convert_html_to_text(html):
    ...

TEMPLATED_EMAIL_PLAIN_FUNCTION = convert_html_to_text

You can globally override the template dir, and file extension using the following variables in settings.py :

TEMPLATED_EMAIL_TEMPLATE_DIR = 'templated_email/' #use '' for top level template dir, ensure there is a trailing slash
TEMPLATED_EMAIL_FILE_EXTENSION = 'email'

You can also set a value for template_prefix and template_suffix for every time you call send_templated_mail, if you wish to store a set of templates in a different directory. Remember to include a trailing slash.

Using with Django Anymail

Anymail integrates several transactional email service providers (ESPs) into Django, with a consistent API that lets you use ESP-added features without locking your code to a particular ESP. It supports Mailgun, Postmark, SendGrid, SparkPost and more.

You can use it with django-templated-email, just follow their instructions in their quick start to configure it.

Optionally you can use their custom EmailMessage class with django-templated-email by using the following settings:

# This replaces django.core.mail.EmailMessage
TEMPLATED_EMAIL_EMAIL_MESSAGE_CLASS='anymail.message.AnymailMessage'

# This replaces django.core.mail.EmailMultiAlternatives
TEMPLATED_EMAIL_EMAIL_MULTIALTERNATIVES_CLASS='anymail.message.AnymailMessage'

Inline images

You can add inline images to your email using the InlineImage class.

First get the image content from a file or a ImageField:

# From a file
with open('pikachu.png', 'rb') as pikachu:
  image = pikachu.read()

# From an ImageField
# Suppose we have this model
class Company(models.Model):
  logo = models.ImageField()

image = company.logo.read()

Then create an instance of InlineImage:

from templated_email import InlineImage

inline_image = InlineImage(filename="pikachu.png", content=image)

Now pass the object on the context to the template when you send the email.

send_templated_mail(template_name='welcome',
                    from_email='[email protected]',
                    recipient_list=['[email protected]'],
                    context={'pikachu_image': inline_image})

Finally in your template add the image on the html template block:

<img src="{{ pikachu_image }}">

Note: All InlineImage objects you add to the context will be attached to the e-mail, even if they are not used in the template.

Add link to view the email on the web

# Add templated email to INSTALLED_APPS
INSTALLED_APPS = [
  ...
  'templated_email'
]
# and this to your url patterns
url(r'^', include('templated_email.urls', namespace='templated_email')),
# when sending the email use the *create_link* parameter.
send_templated_mail(
    template_name='welcome', from_email='[email protected]',
    recipient_list=['[email protected]'],
    context={}, create_link=True)

And, finally add the link to your template.

<!-- With the 'if' the link will only appear on the email. -->
{% if email_uuid %}
  <!-- Note: you will need to add your site since you will need to access
             it from the email -->
  You can view this e-mail on the web here:
  <a href="http://www.yoursite.com{% url 'templated_email:show_email' uuid=email_uuid %}">
    here
  </a>
{% endif %}
Notes:
  • A copy of the rendered e-mail will be stored on the database. This can grow if you send too many e-mails. You are responsible for managing it.
  • If you use InlineImage all images will be uploaded to your media storage, keep that in mind too.

Class Based Views

It's pretty common for emails to be sent after a form is submitted. We include a mixin to be used with any view that inherit from Django's FormMixin.

In your view add the mixin and the usual Django's attributes:

from templated_email.generic_views import TemplatedEmailFormViewMixin

class AuthorCreateView(TemplatedEmailFormViewMixin, CreateView):
    model = Author
    fields = ['name', 'email']
    success_url = '/create_author/'
    template_name = 'authors/create_author.html'

By default the template will have the form_data if the form is valid or from_errors if the form is not valid in it's context.

You can view an example here

Now you can use the following attributes/methods to customize it's behavior:

Attributes:

templated_email_template_name (mandatory if you don't implement templated_email_get_template_names()):
String naming the template you want to use for the email. ie: templated_email_template_name = 'welcome'.
templated_email_send_on_success (default: True):
This attribute tells django-templated-email to send an email if the form is valid.
templated_email_send_on_failure (default: False):
This attribute tells django-templated-email to send an email if the form is invalid.
templated_email_from_email (default: settings.TEMPLATED_EMAIL_FROM_EMAIL):
String containing the email to send the email from.

Methods:

templated_email_get_template_names(self, valid) (mandatory if you don't set templated_email_template_name):
If the method returns a string it will use it as the template to render the email. If it returns a list it will send the email only with the first existing template.
templated_email_get_recipients(self, form) (mandatory):
Return the recipient list to whom the email will be sent to. ie:
def templated_email_get_recipients(self, form):
    return [form.data['email']]
templated_email_get_context_data(**kwargs) (optional):
Use this method to add extra data to the context used for rendering the template. You should get the parent class's context from calling super. ie:
def templated_email_get_context_data(self, **kwargs):
    context = super(ThisClassView, self).templated_email_get_context_data(**kwargs)
    # add things to context
    return context
templated_email_get_send_email_kwargs(self, valid, form) (optional):
Add or change the kwargs that will be used to send the e-mail. You should call super to get the default kwargs. ie:
def templated_email_get_send_email_kwargs(valid, form):
  kwargs = super(ThisClassView, self).templated_email_get_send_email_kwargs(valid, form)
  kwargs['bcc'] = ['[email protected]']
  return kwargs
templated_email_send_templated_mail(*args, **kwargs) (optional):
This method calls django-templated-email's send_templated_mail method. You could change this method to use a celery's task for example or to handle errors.

Future Plans

See https://github.com/vintasoftware/django-templated-email/issues?state=open

Using django_templated_email in 3rd party applications

If you would like to use django_templated_email to handle mail in a reusable application, you should note that:

  • Your calls to send_templated_mail should set a value for template_dir, so you can keep copies of your app-specific templates local to your app (although the loader will find your email templates if you store them in <your app>/templates/templated_email, if TEMPLATED_EMAIL_TEMPLATE_DIR has not been overridden)
  • If you do (and you should) set a value for template_dir, remember to include a trailing slash, i.e. 'my_app_email/'
  • The deployed app may use a different backend which doesn't use the django templating backend, and as such make a note in your README warning developers that if they are using django_templated_email already, with a different backend, they will need to ensure their email provider can send all your templates (ideally enumerate those somewhere convenient)

Notes on specific backends

Using vanilla_django

This is the default backend, and as such requires no special configuration, and will work out of the box. By default it assumes the following settings (should you wish to override them):

TEMPLATED_EMAIL_TEMPLATE_DIR = 'templated_email/' #Use '' for top level template dir
TEMPLATED_EMAIL_FILE_EXTENSION = 'email'

For legacy purposes you can specify email subjects in your settings file (but, the preferred method is to use a {% block subject %} in your template):

TEMPLATED_EMAIL_DJANGO_SUBJECTS = {
    'welcome':'Welcome to my website',
}

Additionally you can call send_templated_mail and optionally override the following parameters:

template_prefix='your_template_dir/'  # Override where the method looks for email templates (alternatively, use template_dir)
template_suffix='email'               # Override the file extension of the email templates (alternatively, use file_extension)
cc=['[email protected]']              # Set a CC on the mail
bcc=['[email protected]']             # Set a BCC on the mail
template_dir='your_template_dir/'     # Override where the method looks for email templates
connection=your_connection            # Takes a django mail backend connection, created using **django.core.mail.get_connection**
auth_user='username'                  # Override the user that the django mail backend uses, per **django.core.mail.send_mail**
auth_password='password'              # Override the password that the django mail backend uses, per **django.core.mail.send_mail**

Releasing a new version of this package:

Update CHANGELOG file.

Execute the following commands:

bumpversion [major,minor,patch]
python setup.py publish
git push origin --tags

Commercial Support

This library, as others, is used in projects of Vinta clients. We are always looking for exciting work, so if you need any commercial support, feel free to get in touch: [email protected]

Comments
  • Bump version number on PyPi with new Django 1.8 fix

    Bump version number on PyPi with new Django 1.8 fix

    Currently doing a "pip install django-templated-email" will break a Django 1.8 instance as the latest compatibility code hasn't been put into pypi.

    opened by bradbeattie 15
  • Template' object is not iterable

    Template' object is not iterable

    Hi, when I try to send a mail I got Template' object is not iterable

    I found in utils.py this part: for node in template

    but template is not a list. Instead I can fix and get app running if I make something like:

    for node in template.template.nodelist:

    It's my problem? Anyone else?

    Thanks.

    opened by acarmisc 12
  • Problem found when extending an email template

    Problem found when extending an email template

    When extending an email template I get an error, I think it's because the template doesn't have the plain/html blocks.... I'm having this error:

    UnboundLocalError at /checkout/thanks/ local variable 'e' referenced before assignment

    in vanilla_django.py on line 138: return e.extra_headers.get('Message-Id',None)

    opened by julian-amaya 12
  • Explicit template name for third party integration

    Explicit template name for third party integration

    I'm trying to use django-templated-email as a backed for a third party app that provides some default email templates. The usual method for html templates in apps tries to namespace itself like <app name>/my_template.html under the path <app name>/templates/<app name>/my_template.html, which can be found using the app directories template loader and thus the get_template function call.

    My problem is the implicit template path generation from TEMPLATED_EMAIL_FILE_EXTENSION and TEMPLATED_EMAIL_TEMPLATE_DIR settings. If the user changes these settings my pluggable app will break since I would place my templates according to the defaults into the following location <app name>/templates/templated_email/my_template.email. Therefore the user would either be stuck using default settings or copy/sylink templates to another app. Can you enlighten me as to why the default behavior doesn't just try to load the template.email file from regular template loaders? I think that naming the templates like <app name>/templates/<app name>/my_template.email as a non-enforced best practice would be fairly self-explanatory and then you can just pass os.path.join(<app_name>, my_template.email) as the template_name insend_templated_mail`.

    I understand that this might break backwards compatibility so perhaps we can add a kwarg to send_templated_mail called template that would just try to load the template as an explicit path for a loader and we can maintain both template_name and template as arguments that can be passed in.

    opened by yesimon 7
  • Use 3rd party package for rendering template blocks

    Use 3rd party package for rendering template blocks

    This is similar to #38, but actually uses a separate package (django-render-block). This is based on the snippets used to make Django-Block-Render, but updated and with a lot more features:

    • Tests
    • Supports Django 1.8/1.9/1.10
    • Set up to support more than just Django templates (I have partial support for Jinja2 as well)
    • pip installable (and on pypi)

    In full disclosure, the django-render-block package is mine.

    The single test added in this is pretty lame, but I wasn't sure what else to add. Suggestions are welcome! (Note the tests will pass without the change here. :)) If there's a particular behavior you want tested in terms of template inheritance, etc. they'd probably make more sense as part of the django-render-block repo.

    Fixes #28 Fixes #46

    opened by clokep 6
  • Can't use a custom connection/EmailBackend when using django's mail sender (and consequently set auth_user/password per mail)

    Can't use a custom connection/EmailBackend when using django's mail sender (and consequently set auth_user/password per mail)

    Hi -

    When sending out an email with eg this code:

    send_templated_mail(
            template_name='error-in-validation',
            from_email='[email protected]',
            recipient_list=['[email protected]'],
            context={
                'key': key
            },
        )
    

    the from_email is overwritten with my EMAIL_HOST_USER setting. In Django, while sending a message, it's possible to give extra parameters (auth_user and auth_password) to override the default settings. Is this possible with django-templated-email?

    Thanks!

    opened by LaundroMat 6
  • The subject block cannot be overwrite when inherit the email template.

    The subject block cannot be overwrite when inherit the email template.

    Is the subject block treated specially and did not get into the Django template inheritance process? I had to use this work around that is put this in my base.email {% block subject %}{{ subject }}{% endblock %}

    And every time when call send email, the context need to have the subject line.

    opened by sunshineo 5
  • Backend shortcuts

    Backend shortcuts

    TEMPLATED_EMAIL_BACKEND = 'templated_email.backends.vanilla_django.TemplateBackend' is more than 80 chars length. It would be nice to have some sort of shortcut for this :)

    opened by zerko 5
  • Auto-escape only the HTML part

    Auto-escape only the HTML part

    This PR enables auto-escaping on the HTML part but not on the plain text and subject parts. It fixes #108, fixes #109, and closes #111 with a simpler alternative that doesn't rely on html.parser.

    It relies on https://github.com/clokep/django-render-block/pull/21, that's why I bumped the requirement to django-render-block==0.8.

    opened by bblanchon 4
  • Strip whitespace out of email subject

    Strip whitespace out of email subject

    Templates often add a lots of whitespace around content. While this is not a thing for web browsers, email client shows whitespace in subject. Keeping template clean of whitespace is not an option since most of IDE would like to reformat template with indentation.

    opened by xy2 4
  • Migrating the project

    Migrating the project

    Even though I have permission to commit in this repository I don't have permission to publish it in pypi. We lost touch with the old developer @BradWhittington .

    I will leave this issue open for a few days and if there is no objection we will create a new Pypi package and migrate the project there, that's the only way to go forward with the project.

    opened by aericson 4
  • [FEATURE SUGGESTION] Provide an admin interface for templates

    [FEATURE SUGGESTION] Provide an admin interface for templates

    Thanks for maintaining this repo! I have a feature suggestion that would really help some nontechnical members of my team.

    A really nice feature to have would be an admin interface for non-technical users to view templates and, ideally using a WYSIWYG editor, edit the templates.

    For templates built in a html file, providing a read-only admin interface would be nice as well, including the template as well as the to, from, subject, etc. fields that are part of the email.

    Is this something that would be a welcome addition? Any thoughts on whether this would be reasonably doable? For a WYSIWYG editor it would likely mean storing those templates that use WYSIWYG in the database.

    Thanks again fro maintaining django templated email, and for considering this!

    opened by YPCrumble 1
  • Allow empty from_email param

    Allow empty from_email param

    Resolves #97

    The context and recipient_listparams also had to be set as default=None otherwise it wouldn't be possible to set from_email=None.

    It doesn't change the order of the params, so it's not a breaking change.

    It also removes the empty context params {} which are not required anymore.

    opened by tuliolages 1
Releases(3.0.1)
Owner
Vinta Software
Python, Django and React Experts
Vinta Software
Djrill is an email backend and new message class for Django users that want to take advantage of the Mandrill transactional email service from MailChimp.

Djrill: Mandrill Transactional Email for Django Djrill integrates the Mandrill transactional email service into Django. PROJECT STATUS: INACTIVE As of

Brack3t 327 Oct 1, 2022
PGP encrypted / multipart templated emails for Django

Created by Stephen McDonald Introduction django-email-extras is a Django reusable app providing the ability to send PGP encrypted and multipart emails

stephenmcd 75 May 14, 2022
Churn Emails Inbox - Churn Emails Inbox Using Python

Churn Emails Inbox In this project, I have used the Python programming langauge

null 2 Nov 13, 2022
An API to send emails through python3's smtplib module.

An API to send emails through python3's smtplib module. Just configure your SMTP server credentials and you are ready to send a lot of emails through API, designed to be used as a newsletter service.

Adnan Ahmad 15 Nov 24, 2022
Envia-emails - A Python Program that creates emails

Envia-emails Os emails é algo muito importante e usado. Pensando nisso, eu criei

José Rodolfo 2 Mar 5, 2022
A Django app that allows you to send email asynchronously in Django. Supports HTML email, database backed templates and logging.

Django Post Office Django Post Office is a simple app to send and manage your emails in Django. Some awesome features are: Allows you to send email as

User Inspired 856 Dec 25, 2022
Bulk send personalized emails using a .csv file and Gmail API (via EZGmail)

GSender Bulk send personalized emails using a .csv file and Gmail API (via EZGmail). Installation Install requirements.txt. Follow the EZGmail Install

null 1 Nov 23, 2021
Send Emails through the terminal , fast and secure

Send Emails through the terminal , fast and secure

null 11 Aug 7, 2022
Convert emails without attachments to pdf and send as email

Email to PDF to email This script will check an imap folder for unread emails. Any unread email that does not have an attachment will be converted to

Robert Luke 21 Nov 22, 2022
A spammer to send mass emails to teachers. (Education Purposes only!)

Securly-Extension-Spammer A spammer to send mass emails to teachers. (Education Purposes only!) Setup Just go a securly blocked page(You can do this b

null 3 Jan 25, 2022
Pysces (read: Pisces) is a program to help you send emails with an user-customizable time-based scheduling.

Pysces (Python Scheduled-Custom-Email-Sender) Pysces (read: Pisces) is a program to help you send emails with an user-customizable time-based email se

Peter 1 Jun 16, 2022
This Tool Is For Sending Emails From A Terminal(Termux/Kali) etc.

This is a Basic python script to send emails from a Terminal(Termux/Kali) are the only tested currently.

AnonyVox 2 Apr 4, 2022
Automatically Send Custom Named Certificates via Mail

Welcome to Certificate Launchpad ?? Automatically Send Custom Named Certificates via Email Intro After any event, sending certificates to attendees or

Dc7 16 Oct 16, 2022
Send Multiple Mail From List With Python

Send Multiple Mail From List With Python You can send multiple e-mail using HTML themes with Python. Here is the e-mail information to be sent. #The m

Mücahid Eker 1 Dec 23, 2021
Use Django admin to manage drip campaign emails using querysets on Django's User model.

Django Drip Drip campaigns are pre-written sets of emails sent to customers or prospects over time. Django Drips lets you use the admin to manage drip

Zapier 630 Nov 16, 2022
A functional demo of the O365 Module to send an email on an authenticated, tokenized account.

O365_email A functional demo of the O365 Module to send an email on an authenticated, tokenized account. Prep Create an app in Azure Developer's porta

null 2 Oct 14, 2022
A script based on an article I wrote on decluttering emails.

Decluttering_Email A script based on an article I wrote on decluttering emails. What does this program do? This program is a python script that sends

Ogheneyoma Obomate Okobiah 6 Oct 21, 2021
Mailrise is an SMTP server that converts the emails it receives into Apprise notifications

Mailrise is an SMTP server that converts the emails it receives into Apprise notifications. The intended use case is as an email relay for a home lab or network. By accepting ordinary email, Mailrise enables Linux servers, Internet of Things devices, surveillance systems, and outdated software to gain access to the full suite of 60+ notification services supported by Apprise, from Matrix to Nextcloud to your desktop or mobile device.

Ryan Young 293 Jan 7, 2023
Heimdall watchtower automatically sends you emails to notify you of the latest progress of your deep learning programs.

This software automatically sends you emails to notify you of the latest progress of your deep learning programs.

Zhenyue Qin 22 Dec 6, 2021