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
Disposable Temporary Email (Python Library)

Disposable Temporary Email (Python Library)

krypton 13 Nov 24, 2022
A light-weight, modular, message representation and mail delivery framework for Python.

Marrow Mailer A highly efficient and modular mail delivery framework for Python 2.6+ and 3.2+, formerly called TurboMail. © 2006-2019, Alice Bevan-McG

Marrow Open Source Collective 255 Dec 28, 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
Suplantar mails de empresas como google, facebook, github, etc...

Suplantar mails de empresas como google, facebook, github, etc...

piter 3 Feb 05, 2022
SMTP checker to check Mail Access via SMTP

SMTP checker to check Mail Access via SMTP with easy usage ! Medusa has been written and tested with Python 3.8. It should run on any OS as long as Python and all dependencies are installed.

h3x0 23 Dec 05, 2022
xxnx its a simple smtp tool for mails spaming

xxnx its a simple smtp tool for mails spaming what is smpt? Simple Mail Transfer Protocol or smtp service. The Simple Mail Transfer Protocol (SMTP) is

0xD4$H 3 Feb 27, 2022
Dotfiles and some scripts for NeoMutt

Mutt dotfiles Robust Mutt configs with examples for the following account types: Generic IMAP/SMTP Google (Gmail/Gsuite etc) via IMAP/SMTP Microsoft O

CEUK 29 Jan 04, 2023
Read/sync your IMAP mailboxes (python2)

Upstream status (master branch): Upstream status (next branch): Financial contributors: Links: Official github code repository: offlineimap Website: w

OfflineIMAP 1.7k Dec 29, 2022
Generate Email, Register for anything, Get the OTP/Link

OTE : One Time Email Introduction ote is a command line utility that generates temporary email address and automatically extracts OTPs or confirmation

Somdev Sangwan 457 Jan 03, 2023
利用阿里的云函数发送电子邮件

alifc_email 主要特性 利用阿里的云函数发送电子邮件 使用场景 hw中的钓鱼邮件发送,一些邮服会解析出邮件的来源ip(此来源ip并不是邮服的ip,而是从客户端发送邮件时,邮服自动带上的客户端ip),对于这些来源ip可能会做一些风控。 本项目利用云函数出口ip较多来绕过这些风控 使用方法 首

19 Dec 01, 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
Fast Anonymous Email Sending Tool

Email-Fake Fast Anonymous Email Sending Tool 🏆 Github Statistics : Termux For Install: pkg install python pkg install python2 git clone https://githu

Aryan 7 May 28, 2022
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

Ryan Young 293 Jan 07, 2023
This library is helpful when creating accounts, it has everything you need for this

AccountGeneratorHelper Library to facilitate accounts generation. Unofficial API for temp email services. Receive SMS from free services. Parsing and

Denis 52 Jan 07, 2023
EmailAll - a powerful Email Collect tool

EmailAll A powerful Email Collect tool 0x1 介绍 😲 EmailAll is a powerful Email Co

473 Dec 22, 2022
A Django email backend for Amazon's Simple Email Service

Django-SES Info: A Django email backend for Amazon's Simple Email Service Author: Harry Marr (http://github.com/hmarr, http://twitter.com/harrymarr) C

882 Dec 29, 2022
Certificate generating and mailing system

skylab-certificate-system Through the this system, you can generate personalized certificates for people with name-surname-mail information in an exce

Oğuzhan Ercan 9 Sep 27, 2022
Mail hosting made simple

Modoboa Modoboa is a mail hosting and management platform including a modern and simplified Web User Interface. It provides useful components such as

Modoboa 2.4k Jan 03, 2023
Send e-mails asyncronously using cron

django-yubin Django Yubin allows the programmer to control when he wants to send the e-mail in this application, making the web application to answer

APSL 44 Sep 24, 2022
Collection of emails sent from the Hungarian gov and Viktor Orbán to the citizens of Hungary

Public list of Hungary and Viktor Orbán's emails since March 2021 Collection of emails sent from the Hungarian government and Viktor Orbán to the citi

Miguel Sozinho Ramalho 1 Mar 28, 2022