This post shows how you can send triggered emails asynchronously through Amazon's SES (Simple Email Service) using Django, Celery and RabbitMQ.
First up install and run RabbitMQ:
- Install:
sudo apt-get install rabbitmq-server
- Run:
rabbitmq-server
Next install Celery following the instructions
here (make sure you add the
following to settings.py
):
import djcelery
djcelery.setup_loader()
BROKER_URL = "amqp://guest:guest@localhost:5672//"
Finally install Django SES using this guide. Make sure you verify a sending address with Amazon and add it to your settings file:
EMAIL_FROM_ADDR = "do-not-reply@yourverifieddomain.com"
Before writing any email tasks Celery needs to be started. In development mode
you can run the following: python manage.py celeryd -B -E -l info
but in
production you will probably want to use something like Supervisor to ensure the
process is always running. You could do something like the following:
/etc/supervisor/conf.d/project_name_celery.conf
:
[program:project_name_celery]
directory = /path/to/project
user = username
command = /path/to/project/config/celery.sh
stdout_logfile = /path/to/logfile
stderr_logfile = /path/to/errlog
/path/to/project/config/celery.sh
#!/bin/bash
set -e
cd /path/to/project
source /path/to/virtualenv/bin/activate
python manage.py celeryd -B -E -l info
Now everything is installed and Celery and RabbitMQ are running, tasks and triggers can be created. Creating an email task:
# app/tasks.py
from django.conf import settings
from djcelery import celery
from .services import Email
@celery.task
def send_trigger_email(*args, **kwargs):
email = Email(to=kwargs.get('to'), subject=kwargs.get('subject'))
context = {
'username': kwargs.get('username', ''),
'confirmation_id': kwargs.get('confirmation_id', '')
}
email.text('{0}/emails/{1}.txt'.format(
settings.TEMPLATE_DIRS[0], kwargs.get('template')), context)
email.html('{0}/emails/{1}.html'.format(
settings.TEMPLATE_DIRS[0], kwargs.get('template')), context)
email.send()
The Email class I have used can be found here. The templates are just standard Django templates, here is an example of what a text version of an email could look like:
Thanks for your order
=====================
Hey {{ username }}, thanks for your recent order. Your confirmation number
is {{ confirmation_id }}.
Thanks
Web team
How to trigger the email send:
# app/admin.py
from django.contrib import admin
from .tasks import send_trigger_email
class MyAppAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
# ...
email_data = {
'to': email,
'subject': 'Thanks for your order',
'username': username,
'confirmation_id': confirmation_id,
'template': 'confirm'
}
send_trigger_email.delay(**email_data)
super(MyAppAdmin, self).save_model(
request, obj, form, change
)
Calling the task with delay
ensures it will be processed asynchronously.