Email Guide
Django provides a comprehensive email sending framework that supports text and HTML emails, attachments, and multiple backends.
Overview
Django’s email system consists of:
- Email backends - SMTP, Console, File, Memory, Dummy
- Email classes -
EmailMessage, EmailMultiAlternatives
- Helper functions -
send_mail(), send_mass_mail()
- Email utilities - Attachments, headers, threading
Quick Start
Configure Email Settings
Add email configuration to settings.py:# SMTP Configuration
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'your-app-password'
DEFAULT_FROM_EMAIL = 'Your Name <[email protected]>'
Send Your First Email
Use the send_mail() function:from django.core.mail import send_mail
send_mail(
subject='Hello from Django',
message='This is a test email.',
from_email='[email protected]',
recipient_list=['[email protected]'],
fail_silently=False,
)
Email Backends
SMTP Backend (Production)
# Gmail
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'your-app-password'
# SendGrid
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'apikey'
EMAIL_HOST_PASSWORD = 'your-sendgrid-api-key'
# AWS SES
EMAIL_HOST = 'email-smtp.us-east-1.amazonaws.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
For Gmail, enable 2-factor authentication and create an App Password instead of using your regular password.
Console Backend (Development)
# Print emails to console
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
Emails are printed to stdout:
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Subject: Test Email
From: [email protected]
To: [email protected]
This is a test email.
File Backend (Testing)
# Save emails to files
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = '/tmp/app-emails'
Memory Backend (Testing)
# Store emails in memory (useful for tests)
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
Access sent emails in tests:
from django.core import mail
def test_email_sent(self):
# Send email
send_mail('Subject', 'Message', '[email protected]', ['[email protected]'])
# Check email was sent
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, 'Subject')
Sending Emails
Simple Text Email
from django.core.mail import send_mail
send_mail(
subject='Welcome to Our Site',
message='Thanks for signing up!',
from_email='[email protected]',
recipient_list=['[email protected]'],
fail_silently=False, # Raise exceptions on errors
)
HTML Email
from django.core.mail import send_mail
send_mail(
subject='Welcome!',
message='Plain text version', # Fallback for non-HTML clients
from_email='[email protected]',
recipient_list=['[email protected]'],
html_message='<h1>Welcome!</h1><p>Thanks for signing up!</p>',
)
EmailMessage Class
For more control, use EmailMessage:
HTML Emails with Alternatives
from django.core.mail import EmailMultiAlternatives
subject = 'Welcome'
text_content = 'Thanks for signing up!'
html_content = '<p>Thanks for <strong>signing up</strong>!</p>'
email = EmailMultiAlternatives(
subject=subject,
body=text_content,
from_email='[email protected]',
to=['[email protected]'],
)
email.attach_alternative(html_content, 'text/html')
email.send()
Attachments
Attach Files
from django.core.mail import EmailMessage
email = EmailMessage(
subject='Invoice',
body='Please find your invoice attached.',
from_email='[email protected]',
to=['[email protected]'],
)
# Attach file from filesystem
email.attach_file('/path/to/invoice.pdf')
# Attach file from memory
with open('/path/to/file.pdf', 'rb') as f:
email.attach('document.pdf', f.read(), 'application/pdf')
email.send()
Attach Multiple Files
email = EmailMessage(
subject='Monthly Report',
body='Reports attached.',
from_email='[email protected]',
to=['[email protected]'],
)
# Attach multiple files
email.attach_file('report.pdf')
email.attach_file('data.xlsx')
email.attach_file('chart.png')
email.send()
Inline Images
from django.core.mail import EmailMultiAlternatives
from email.mime.image import MIMEImage
email = EmailMultiAlternatives(
subject='Newsletter',
body='Plain text version',
from_email='[email protected]',
to=['[email protected]'],
)
html_content = '''
<html>
<body>
<h1>Newsletter</h1>
<img src="cid:logo" alt="Logo">
</body>
</html>
'''
email.attach_alternative(html_content, 'text/html')
# Attach image as inline
with open('logo.png', 'rb') as f:
img = MIMEImage(f.read())
img.add_header('Content-ID', '<logo>')
email.attach(img)
email.send()
Mass Mailing
Send Multiple Emails Efficiently
from django.core.mail import send_mass_mail
message1 = (
'Subject 1',
'Message 1',
'[email protected]',
['[email protected]'],
)
message2 = (
'Subject 2',
'Message 2',
'[email protected]',
['[email protected]'],
)
message3 = (
'Subject 3',
'Message 3',
'[email protected]',
['[email protected]'],
)
# Send all messages using a single SMTP connection
send_mass_mail((message1, message2, message3), fail_silently=False)
Using Email Connection
from django.core.mail import get_connection, EmailMessage
# Open connection once
connection = get_connection()
connection.open()
# Send multiple emails
email1 = EmailMessage('Subject 1', 'Body 1', to=['[email protected]'], connection=connection)
email2 = EmailMessage('Subject 2', 'Body 2', to=['[email protected]'], connection=connection)
email3 = EmailMessage('Subject 3', 'Body 3', to=['[email protected]'], connection=connection)
# Send all at once
connection.send_messages([email1, email2, email3])
# Close connection
connection.close()
Template-Based Emails
Using Django Templates
from django.core.mail import EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
def send_welcome_email(user):
# Render HTML content
html_content = render_to_string('emails/welcome.html', {
'user': user,
'activation_link': 'https://example.com/activate/...',
})
# Create plain text version
text_content = strip_tags(html_content)
# Send email
email = EmailMultiAlternatives(
subject='Welcome to Our Site',
body=text_content,
from_email='[email protected]',
to=[user.email],
)
email.attach_alternative(html_content, 'text/html')
email.send()
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.button { background-color: #4CAF50; color: white; padding: 10px 20px; }
</style>
</head>
<body>
<h1>Welcome, {{ user.get_full_name }}!</h1>
<p>Thanks for joining our community.</p>
<a href="{{ activation_link }}" class="button">Activate Your Account</a>
</body>
</html>
Email to Admins
from django.core.mail import mail_admins, mail_managers
# Email all admins
mail_admins(
subject='Server Error',
message='An error occurred...',
fail_silently=False,
)
# Email all managers
mail_managers(
subject='Important Notice',
message='Please review...',
)
Error Handling
from django.core.mail import send_mail
from smtplib import SMTPException
import logging
logger = logging.getLogger(__name__)
try:
send_mail(
subject='Test',
message='Message',
from_email='[email protected]',
recipient_list=['[email protected]'],
fail_silently=False,
)
except SMTPException as e:
logger.error(f'Email failed to send: {e}')
# Handle error (retry, notify admin, etc.)
except Exception as e:
logger.error(f'Unexpected error: {e}')
Testing Emails
from django.test import TestCase
from django.core import mail
class EmailTestCase(TestCase):
def test_send_email(self):
# Clear outbox
mail.outbox = []
# Send email
mail.send_mail(
'Subject',
'Message',
'[email protected]',
['[email protected]'],
)
# Test that one message has been sent
self.assertEqual(len(mail.outbox), 1)
# Verify email content
email = mail.outbox[0]
self.assertEqual(email.subject, 'Subject')
self.assertEqual(email.body, 'Message')
self.assertEqual(email.from_email, '[email protected]')
self.assertEqual(email.to, ['[email protected]'])
def test_html_email(self):
from django.core.mail import EmailMultiAlternatives
email = EmailMultiAlternatives(
'Subject',
'Text content',
'[email protected]',
['[email protected]'],
)
email.attach_alternative('<p>HTML content</p>', 'text/html')
email.send()
# Check HTML alternative was attached
self.assertEqual(len(mail.outbox), 1)
sent_email = mail.outbox[0]
self.assertTrue(sent_email.body_contains('Text content'))
Best Practices
Use Environment Variables
Never hardcode credentials in settings:import os
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
Use Celery for Async Sending
Send emails asynchronously to avoid blocking requests:from celery import shared_task
from django.core.mail import send_mail
@shared_task
def send_email_task(subject, message, recipient_list):
send_mail(
subject=subject,
message=message,
from_email='[email protected]',
recipient_list=recipient_list,
)
Include Plain Text Versions
Always provide plain text alternatives for HTML emails.
Handle Failures Gracefully
Use fail_silently=False in development, log errors in production.
Common Patterns
User Registration Email
def send_registration_email(user, activation_token):
activation_link = f'https://example.com/activate/{activation_token}'
send_mail(
subject='Activate Your Account',
message=f'Click this link to activate: {activation_link}',
from_email='[email protected]',
recipient_list=[user.email],
)
Password Reset Email
from django.contrib.auth.tokens import default_token_generator
from django.utils.http import urlsafe_base64_encode
from django.utils.encoding import force_bytes
def send_password_reset_email(user):
token = default_token_generator.make_token(user)
uid = urlsafe_base64_encode(force_bytes(user.pk))
reset_link = f'https://example.com/reset/{uid}/{token}/'
send_mail(
subject='Password Reset Request',
message=f'Click here to reset your password: {reset_link}',
from_email='[email protected]',
recipient_list=[user.email],
)
Always use HTTPS for links containing sensitive tokens.
- Email Settings (see api/settings)
- Email Backends (see guides/email)
- Testing Email (see guides/testing)