1. Introduction
djmail is a BSD Licensed, simple and nonobstructive django email middleware. djmail was created by Andrey Antukh <niwi@niwi.nz> and is maintened by David Barragán <bameda@dbarragan.com>
2. Why use djmail?
Because it:
-
Sends emails asynchronously without additional libraries.
-
Sends emails using celery tasks.
-
Can retry sending failed messages (with cron task or celery periodic task).
-
Can assign delivery priority.
-
Has a powerfull class to build emails from templates.
-
Works transparently (works as middleware for native django email backends)
2.1. How to install?
The simplest way to get djmail for your project, is installing it using pip:
pip install djmail
3. User guide
As I have mentioned previously, djmail works as a middleware.
-
It saves emails using django orm and track its status. If an exception is raised during sending, it marks the email as failed and stores the exception traceback for posterior analysis.
-
Exposes usefull commands and methods for retring to send failed messages.
-
Handles priority, with ability to delay sending of messages with lowest priorty to periodic task (with cron or celery).
To get djmail working on your project, you should configure it. An example setup:
INSTALLED_APPS = [
...,
'djmail',
...,
]
EMAIL_BACKEND="djmail.backends.default.EmailBackend"
DJMAIL_REAL_BACKEND="django.core.mail.backends.console.EmailBackend"
This specifies: emails are managed by djmail default backend and actually sent using console based django builtin backend.
3.1. How to use?
djmail works as a middleware, and the simplest way to use it, is to not think, just send emails the way you did before.
3.2. Backends
djmail comes with three backends:
-
djmail.backends.default.EmailBackend
send emails synchronously using real backend. -
djmail.backends.async.EmailBackend
send emails asynchronously using concurrent.futures. -
djmail.backends.celery.EmailBackend
send emails asynchronously using celery tasks.
3.3. Management Commands
djmail has two built-in management commands:
-
djmail_retry_send_messages
Sends all mail in the queue, also retrying previously failed email messages. After the global retry limit is reached, an email is marked as discarded. -
djmail_delete_old_messages --days=183
djmail stores all messages in the database, which could eventually take up a lot of database space for data which is not important to keep. This command deletes all succesfully sent messages older than the provided age (when the --days parameter is ommited, the default value is 6 months).
An example setup using cronjobs (sudo crontab -e) would be
@hourly python manage.py djmail_retry_send_messages @weekly python manage.py djmail_delete_old_messages --days=31
4. Template Emails
djmail comes with two util classes for easily building emails from templates:
-
djmail.template_mail.TemplateMail: low level interface.
-
djmail.template_mail.MagicMailBuilder: high level interface with some magic.
4.1. TemplateMail
This is a low level interface for buiding emails using templates. It allows to statically define email classes for posterior usage:
from djmail import template_mail
# Define a subclass of TemplateMail
class SomeTemplateEmail(template_mail.TemplateMail):
name = "some_email"
# Create a instance
email = SomeTemplateEmail()
# Buld and sent message with specified context
email.send("to@example.com", {"template": "context"})
Also you can obtain a native django email instance from TemplateMail instance:
# Create a instance
template_email = SomeTemplateEmail()
# obtain a native django email object
email = template_email.make_email_object("to@example.com",
{"template": "context"})
email.send()
TemplateMail default implementation searches these templates:
-
emails/some_email-body-html.html
-
emails/some_email-body-text.html
-
emails/some_email-subject.html
Note
|
Text version of email is ommited if template does not exists. |
4.2. MagicMailBuilder
This is a more powerful way for building email messages from templates. Behind the scenes, it uses TemplateMail implementation but exposes a dynamic api that allows building of subclasses on demand.
from djmail import template_mail
# Create MagicMailBuilder instance
mails = template_mail.MagicMailBuilder()
# Create a native email object.
# NOTE: The method name represents a email name.
email = mails.some_email("to@example.com", {"template": "context"})
email.send()
Additionally, instead of receiver email address you can pass a django model instance that represents a user (it should have "email" field for work):
class MyUser(models.Model):
email = models.CharField(max_length=200)
lang = models.CharField(max_length=200, default="es")
# [...]
user = MyUser.objects.get(pk=1)
email = mails.some_email(user, {"template": "context"})
Magic builder is really magic, and if your user class has lang field, magic builder uses it to setup a correct user language for rendering email in user locale.
Note
|
Also, you can specify a custom "lang" on context for same purpose. |
5. Settings
djmail exposes some additional settings for costumizing a great part of default behavior.
-
DJMAIL_REAL_BACKEND
Indicates to djmail which django email backend to use for delivering email messages.
Default: django.core.mail.backends.console.EmailBackend -
DJMAIL_MAX_RETRY_NUMBER
Set a default maximum retry number for delivering failed messages.
Default: 3 -
DJMAIL_BODY_TEMPLATE_PROTOTYPE
Prototype for making body template path.
Default: emails/{name}-body-{type}.{ext} -
DJMAIL_SUBJECT_TEMPLATE_PROTOTYPE
Prototype for make subject template path.
Default: emails/{name}-subject.{ext} -
DJMAIL_TEMPLATE_EXTENSION
Extension used for build a final path of email templates.
Default: html
6. License
Copyright (c) 2013-2015 Andrey Antukh <niwi@niwi.nz>
Copyright (c) 2015-2020 David Barragan <bameda@dbarragan.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.