Published 2021-05-18.
Time to read: 2 minutes.
django
collection.
Argh, gather around, and I'll tell ye a tale of the secrets of setting Up Django email. Yon scurvey dogs tend to leave out some important information in the documentation. Even those dastardly cretins answering questions at StackOverflow won’t tell the full tale, not with all the important juicy bits.
EMail Server Settings
These are the DJango settings I use to send email from one of
Rackspace EMail accounts.
Notice how I have highlighted a portion of the EMAIL_BACKEND
value (smtp
).
That is the backend
which will actually send email, instead of merely accepting the email request and logging it without actually sending anything email.
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'secure.emailsrvr.com'
EMAIL_HOST_PASSWORD = '****'
EMAIL_HOST_USER = 'email@domain.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_USE_SSL = False
This is the underdocumented backend that will cause you untold grief if you don't know about it:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Unfortunately, some overly helpful but horribly misguided soul decided to make the console email backend the default. That backend does not actually send email, it is just a stub.
Unit Tests Change the Middleware Without Warning
In an outstanding display of misguided overworking of an API, when in unit test mode, Django changes the middleware without notice. The documentation does mention this misbehavior, if you know where to look. You'll never find that information unless you know it is there.
The middleware that gets swapped in also does not actually send email. No, your code is not broken, you are caught between a poor design decision and inadequate documentation. I highlighted the magic pixie dust you need to make emails work in unit tests.
from django.test import TestCase from django.test.utils import override_settings
# Import EMAIL_BACKEND so the value can be used to override # Django's misguided email middleware switcheroo for unit tests from main.settings import EMAIL_BACKEND from thing_model.models import ThingModel
class ThingModelTests(TestCase):
# See https://stackoverflow.com/a/49909468/553865 @override_settings(EMAIL_BACKEND=EMAIL_BACKEND) def test_result_html(self): thing_model.email("blah@blah.com")
HTML and/or Text EMail
Django can send plain text email, or HTML email, or both together. Here is a simplified example of how to send information from a model class as HTML and plaintext using Django email.
from django.db import models from django.core.mail import send_mail class ThingModel(models.Model): # Define model fields here @property def as_html(self): return "<h2>Title goes here</h2>\n<p>Blah blah</p>\n" @property def as_text(self): return "Title goes here\nBlah blah\n" def email(self, email_address): # result is set to 1 for success, 0 for failure result = send_mail( subject = 'Test Email', message = self.as_text, html_message = self.as_html, from_email = 'email@domain.com', recipient_list = [ email_address ], ) print(f"Result code for sending email={result}")