A Simple SMTP Mail Queue Backend for Django
Our clients frequently ask for the capability to send emails from their website. Whether the email is a receipt for a product just purchased or a contact form submission, we wanted to make sure that those emails got to their destination every single time. We use Django for our backend CMS and unfortunately Django's handling of the Simple Mail Transfer Protocol (SMTP) is not resilient enough for us. If a SMTP server is down, or cannot be connected to due to network issues: Django simply fails with a 500 error. When our SMTP server is down, which it is 0.01% of the time (pretty good!), we wanted to make sure that emails were not lost. Luckily Django allows developers to change out the SMTP backend. So I did just that and created a mail queue.
The mail queue runs on each of our client servers. When an email is sent from the server it is first stored in the mail queue. Every so often this queue is checked for emails, and those emails are then passed on to our SMTP server. If anything fails in the process of connecting or transmitting that email to our SMTP server, the email is simply queued again. The next time the queue is checked it will reattempt the failed email for up to 24 hours after it entered the queue. This ensures that our very small downtime windows on our SMTP server will not affect the delivery of emails from our clients' servers (for very long anyway).
So why are we telling the world? Because we open sourced it! You can find the module, named 'django-mailqueue-backend', at Bitbucket or PyPI (BSD License). Why didn't we use a solution built already? We were looking for simplicity and all we found was complexity. Other queues use Django models, while we use an in-memory key-value store. Other solutions had an admin interface to look at the emails in the queue, we did not see the need for this as the majority of emails would only live in the queue for minutes at most. Others required that you send directly through their API instead of replacing Django's own SMTP backend. Yuck!
Our solution was built with simplicity in mind. We wanted to set it and forget it. Best of all, its simplicity means it is easy to test. With just three unit tests, we have 100% code coverage. We invite you to fork the repo on Bitbucket, but we do plan on keeping the module very simple. We will not accept pull requests that needlessly add features. We designed the module with extensibility in mind, so one can simply build on top of it to add new features for their own use cases. We hope others find this module as useful as we have!