Sending E-Mails via Templates

Posted by Ross Poulton on Tue 11 July 2006 #geeky #django #programming

So you've got an application written in Django that needs to send large bodies of e-mail, but you don't want the e-mail message itself to be in your Python code. Fair enough, I'd say - you should be separating form from function, and in this case, the e-mail output is still what I'd classify as 'form'.

One way to tackle this situation is to create a template for your e-mail body, process that template to fill in the gaps (eg Username, URL's, etc) and shoot it off via Django's e-mail functions instead of rendering it in a web browser as you'd normally do with templates.

First things first - create your template. In this case I'm writing an e-mail to a user thanking them for registering on a website. I've put the template in my templates directory, called email.txt in the registration subdirectory.

Dear {{ name }},

Thank you for signing up with {{ product_name }}.

Your new username is {{ username }}, and you can login at {{ login_url }}. Once logged in, you'll be able to access more features on our website..

We hope that {{ product_name }} is of good use to you. If you have any feedback, please respond to this e-mail or submit it to us via our website.

Regards,

{{ product_name }} Administration
{{ product_url }}

Pretty simple huh? We're using the same syntax used by standard Django templates, where variable names are enclosed in double-curly-braces.

Next, in your code where you want to send the e-mail, load and compile the template and template context:

from django.template import loader, Context

t = loader.get_template('registration/email.txt')
c = Context({
    'name': new_data['first_name'],
    'product_name': 'Your Product Name',
    'product_url': 'http://www.yourproject.com/',
    'login_url': 'http://www.yourproject.com/login/',
    'username': new_data['username'],
})

What this will do is load your e-mail template into memory, and save it in an object t. Next, it creates a template context, c, with 5 variables in it. These variables share the names in the template above - and in this example, three of them (product name and the two URL's) are hard-coded, and the other two come from a dictionary called new_data.

Lastly, we need to join the context and the template together, and send it off in an e-mail:

from django.core.mail import send_mail

send_mail('Welcome to My Project', t.render(c), 'from@address.com', [new_data['email']], fail_silently=False)

Most of this is pretty straightforward - the e-mail subject will be Welcome to My Project, and you've defined a from e-mail address and recipient (again from the new_data dictionary). The funky business is the rendering of the template. The t.render(c) portion simply tells Django, that for template t (defined above), it should use the context c (also defined above), substitute the variables, and return the output. This output becomes the body of the message that the user receives:

Dear Ross,

Thank you for signing up with Your Product Name.

Your new username is rossp, and you can login at http://www.yourproject.com/login/. Once logged in, you'll be able to access more features on our website..

We hope that Your Product Name is of good use to you. If you have any feedback, please respond to this e-mail or submit it to us via our website.

Regards,

Your Product Name Administration
http://www.yourproject.com/

Good luck!