I haven’t written one of these supposedly weekly posts with small Django tips for a while, but at least I always post them on Fridays.
This time I gonna address how we can test emails with the tools that Django provides and more precisely how to check the attachments of those emails.
The testing behavior of emails is very well documented (Django’s documentation is one of the best I’ve seen) and can be found here.
Summing it up, if you want to test some business logic that sends an email, Django replaces the EMAIL_BACKEND
setting with a testing backend during the execution of your test suite and makes the outbox available through django.core.mail.outbox
.
But what about attachments? Since each item on the testing outbox is an instance of the EmailMessage
class, it contains an attribute named “attachments” (surprise!) that is list of tuples with all the relevant information:
("<filename>", "<contents>", "<mime type>")
Here is an example:
# utils.py
from django.core.mail import EmailMessage
def some_function_that_sends_emails():
msg = EmailMessage(
subject="Example email",
body="This is the content of the email",
from_email="some@email.address",
to=["destination@email.address"],
)
msg.attach("sometext.txt", "The content of the file", "text/plain")
msg.send()
# tests.py
from django.test import TestCase
from django.core import mail
from .utils import some_function_that_sends_emails
class ExampleEmailTest(TestCase):
def test_example_function(self):
some_function_that_sends_emails()
self.assertEqual(len(mail.outbox), 1)
email_message = mail.outbox[0]
self.assertEqual(email_message.subject, "Example email")
self.assertEqual(email_message.body, "This is the content of the email")
self.assertEqual(len(email_message.attachments), 1)
file_name, content, mimetype = email_message.attachments[0]
self.assertEqual(file_name, "sometext.txt")
self.assertEqual(content, "The content of the file")
self.assertEqual(mimetype, "text/plain")
If you are using pytest-django
the same can be achieved with the mailoutbox
fixture:
import pytest
from .utils import some_function_that_sends_emails
def test_example_function(mailoutbox):
some_function_that_sends_emails()
assert len(mailoutbox) == 1
email_message = mailoutbox[0]
assert email_message.subject == "Example email"
assert email_message.body == "This is the content of the email"
assert len(email_message.attachments) == 1
file_name, content, mimetype = email_message.attachments[0]
assert file_name == "sometext.txt"
assert content == "The content of the file"
assert mimetype == "text/plain"
And this is it for today.