Testing Emails with Django
Django ticket #8638 titled, "Provide setting to disable e-mail sending", caught my eye as an interesting item to look into. As I looked into it, however, I came up with a pretty simple way to set up testing that involves some settings.py changes and about 4 lines of Python code.
The big piece of magic comes from Python's built-in smtpd library and the smtpd.DebuggingServer class, which discards all e-mails sent to it and prints them to stdout.
Let's use the class to create a local mail server that will discard and print all emails sent to it, then update our settings.py file to point to this debugging mail server.
Create a file containing the following:
import smtpd import asyncore server = smtpd.DebuggingServer(('127.0.0.1', 1025), None) asyncore.loop()
I named mine email_debugger.py and ran it by typing python email_debugger.py at the console. It won't output anything until we try to send an email.
In your project's settings.py file (or whatever local settings file you use) change Django's email settings to use this server. I changed the following, making sure override settings that may possibly be set:
EMAIL_HOST = 'localhost' EMAIL_PORT = 1025 EMAIL_HOST_USER = '' EMAIL_HOST_PASSWORD = '' EMAIL_USE_TLS = False DEFAULT_FROM_EMAIL = 'testing@example.com'
Note that the e-mail host and port match those that are in the debugging script.
Now run you project and use whatever email sending routine you'd like to test. While writing this I tested the contact form that runs on this blog locally on my laptop. I entered in some dummy text and the output at the console of the email_debugger.py script looked like this:
---------- MESSAGE FOLLOWS ---------- Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: Website message from rob.cogit8.org From: testing@example.com To: django_manager@example.com Date: Fri, 21 Nov 2008 04:46:09 -0000 Message-ID: <20081121044609.9329.85531@MBP-of-ROB.local> X-Peer: 127.0.0.1 Message from: Rob <website_user@example.com> Message body: I buy my eggs at the cheese shop! ------------ END MESSAGE ------------
As you can see this is pretty useful and shows all the email headers and email body that would normally be sent to your mail server.
Aside
As an aside, the above file that contains the email debugging server code could be replaced with a quick shell command. The Python smtpd library has the ability to run standalone and takes various options. The above script can be replaced with the following command:
python -m smtpd -n -c DebuggingServer localhost:1025
Where to go from here
If you take a look at the smtpd.py file, you'll notice the DebuggingServer class simply defines a single method process_message. If you wanted to do something different to these emails, you could subclass the SMTPServer class and define your own process_message that could do anything from output to stdout in a different format, or write the emails to a file that can be read by an email client, or save the emails to a database, etc.
For example, if the project will be sending many emails, we may want the output to be less verbose, say, one line per email. So we could create the following:
import smtpd import asyncore class OneLineDebuggingServer(smtpd.SMTPServer): def process_message(self, peer, mailfrom, rcpttos, data): print "Sending mail to %s" % (','.join(rcpttos)) server = OneLineDebuggingServer(('127.0.0.1', 1025), None) asyncore.loop()
This would also be useful as a Django management command where the management command pulled the EMAIL_HOST and EMAIL_PORT from the settings.py file.
Conclusion
I don't know where ticket 8638 will end up, but hopefully the above is enough to help those wanting to test emails locally and avoid errors from the runserver command in the meantime.
About this entry
Date Posted:
November 20th 2008 at 9:11:42 PM
Tagged:
debug,
django,
email,
testing
Previous Entry:
The 56, 5 Book Meme
Next Entry:
Django and Relativity Updated
Comments
blog comments powered by Disqus