Testing email sending in Django
Solution 1
You can use a file backend for sending emails which is a very handy solution for development and testing; emails are not sent but stored in a folder you can specify!
Solution 2
Django test framework has some built in helpers to aid you with testing e-mail service.
Example from docs (short version):
from django.core import mail
from django.test import TestCase
class EmailTest(TestCase):
def test_send_email(self):
mail.send_mail('Subject here', 'Here is the message.',
'[email protected]', ['[email protected]'],
fail_silently=False)
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, 'Subject here')
Solution 3
If you are into unit-testing the best solution is to use the In-memory backend provided by django.
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
Take the case of use it as a py.test fixture
@pytest.fixture(autouse=True)
def email_backend_setup(self, settings):
settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
In each test, the mail.outbox
is reset with the server, so there are no side effects between tests.
from django.core import mail
def test_send(self):
mail.send_mail('subject', 'body.', '[email protected]', ['[email protected]'])
assert len(mail.outbox) == 1
def test_send_again(self):
mail.send_mail('subject', 'body.', '[email protected]', ['[email protected]'])
assert len(mail.outbox) == 1
Solution 4
Use MailHog
Inspired by MailCatcher, easier to install.
Built with Go - MailHog runs without installation on multiple platforms.
Also, it has a component called Jim, the MailHog Chaos Monkey, which enables you to test sending emails with various problems happening:
What can Jim do?
- Reject connections
- Rate limit connections
- Reject authentication
- Reject senders
- Reject recipients
Read more about it here.
(Unlike original mailcatcher, which failed on me when sending emails with emoji, encoded in UTF-8 and it WASN'T really fixed in the current release, MailHog just works.)
Solution 5
For any project that doesn't require sending attachments, I use django-mailer, which has the benefit of all outbound emails ending up in a queue until I trigger their sending, and even after they've been sent, they are then logged - all of which is visible in the Admin, making it easy to quickly check what you emailing code is trying to fire off into the intertubes.
Related videos on Youtube
Comments
-
RadiantHex almost 4 years
I need to test that my Django application sends e-mails with correct content. I don't want to rely on external systems (like an ad-hoc gmail account), since I'm not testing the actual e-mail service...
I would like to, maybe, store the emails locally, within a folder as they are sent. Any tip on how to achieve it?
-
nemesisdesign about 6 yearsModerators: please lock this question. Lots of spam is being added in the answers, proposing solutions that are ridiculously complex just to promote external services.
-
djvg over 2 yearsIt's all in the docs now: docs.djangoproject.com/en/stable/topics/testing/tools/…
-
-
Steve Jalim over 13 yearsFurther to that, the Message objects created by django-mailer mean you can prod them (and inspect their contents) in unit tests too (I know that there's outbound mailbox support in the test suite for a dummy mailbox, but using django-mailer doesn't send mail unless the management command sends it, which means you can't use that mailbox object)
-
santiagobasulto about 11 years+1 Good answer. But I it's not useful for complex cases, when
send_mail
can't be used. -
Steve Jalim about 11 yearsUpdate, ages on from my original answer: github.com/SmileyChris/django-mailer-2 does support attachments, too
-
Jeewes almost 10 yearsMore info about email backends: docs.djangoproject.com/en/dev/topics/email/#email-backends. Sometimes even simple console backend is enough..
-
nimiq over 8 yearsMore precisely the doc is here: docs.djangoproject.com/en/1.8/topics/email/#in-memory-backend
-
Matt almost 7 yearsHow would you do this if your testing a function which calls send_mail and you therefore can't access
mail
? -
pymarco over 6 years@MatthewDrill you can still access
mail.outbox
whensend_mail
is called in another function. -
Rob over 5 years@pymarco If you import mail from core,
mail.outbox[0].body
will show you the email sent even if thesend_mail
is performed elsewhere. -
Overdrivr over 5 yearsBut is there a way to access the generated email during (automated) testing ?
-
Manel Clos about 5 yearsThis works perfect even with mass sending using send_messages, here: docs.djangoproject.com/en/2.1/topics/email/…