Django Sending Emails
In this section, we will learn how to send emails in Django. We will cover how to configure email settings, create email templates, and send emails from views. Sending emails is a common requirement in web applications, whether for user registration, password resets, or notifications.
SMTP Server Setup Using Docker
Section titled “SMTP Server Setup Using Docker”To test email-sending functionality in your Django application, you can set up a local SMTP server using Docker. This allows you to capture and view emails sent from your application without actually sending them to real email addresses. We will use smtp4dev, a simple SMTP server designed for development and testing purposes.
Official Docs: https://github.com/rnwood/smtp4dev
- Create a
docker-compose.ymlfile with the following content to set up thesmtp4devservice:# docker-compose.ymlservices:smtp4dev:image: rnwood/smtp4dev:v3ports:- '127.0.0.1:5000:80' # Web UI (localhost only)- '127.0.0.1:2525:25' # SMTP (localhost only for development)- '127.0.0.1:1143:143' # IMAP (localhost only for development)- '127.0.0.1:1110:110' # POP3 (localhost only for development) - Run the following command in your terminal to start the SMTP server:
Terminal window cd path/to/your/projectdocker compose up
docker run -p 127.0.0.1:5000:80 -p 127.0.0.1:2525:25 -p 127.0.0.1:1143:143 -p 127.0.0.1:1110:110 rnwood/smtp4dev:v3After running the above command, you can access the SMTP server’s web interface at http://localhost:5000 or http://127.0.0.1:5000. This interface allows you to view all the emails that have been sent through the server, making it easy to test your email functionality without sending real emails.
Email Backends in Django
Section titled “Email Backends in Django”Django provides several built-in email backends that you can use to send emails. The most commonly used backend is the SMTP backend, which allows you to send emails through an SMTP server. Other backends include the console backend (which prints emails to the console), the file backend (which saves emails to a file), and the in-memory backend (which stores emails in memory for testing purposes).
Types of Email Backends
Section titled “Types of Email Backends”- SMTP Backend: This is the default backend that sends emails through an SMTP server. You can configure it with your email provider’s SMTP settings.
- Console Backend: This backend is useful for development and testing. It prints the email content to the console instead of sending it.
- File Backend: This backend saves emails to a specified file on the filesystem.
- InMemory Backend: This backend stores emails in memory for testing purposes.
- Dummy Backend: This backend does nothing with the emails. It’s useful for testing when you don’t want to send or store emails.
Configuring Email Settings in Django
Section titled “Configuring Email Settings in Django”To configure email settings in Django, add the following settings to your settings.py file:
# settings.pyEMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"# or for testing purposes, you can use the console backend# EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"EMAIL_HOST = "localhost" # Use your SMTP server's addressEMAIL_HOST_USER = "" # SMTP username (if required)EMAIL_HOST_PASSWORD = "" # SMTP password (if required)EMAIL_PORT = 2525 # Host SMTP port for local smtp4dev mappingDEFAULT_FROM_EMAIL = "noreply@example.com" # Default sender email addressSettings for smtp4dev
If you’re using smtp4dev for testing, you can use the following settings:
# settings.pyEMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"EMAIL_HOST = "localhost"EMAIL_HOST_USER = ""EMAIL_HOST_PASSWORD = ""EMAIL_PORT = 2525DEFAULT_FROM_EMAIL = "noreply@example.com"Sending Emails from Views
Section titled “Sending Emails from Views”There are several ways to send emails from views in Django.
Types of Email Sending Methods:
send_mail: A simple function for sending a single email. It opens new connections for each email.send_mass_mail: A function for sending multiple emails in a single call.mail_admins: A function for sending emails to site administrators.EmailMessageclass: A more flexible way to create and send emails, allowing for attachments and custom headers.
Using send_mail Function
Section titled “Using send_mail Function”from django.core.mail import send_mailfrom django.http import HttpResponsefrom django.core.mail import BadHeaderError
def send_email_view(request): subject = "Test Email" message = "This is a test email sent from Django." from_email = "noreply@example.com" recipient_list = ["user@example.com"] try: # send_mail arguments: subject, message, from_email, recipient_list send_mail(subject, message, from_email, recipient_list) except BadHeaderError: return HttpResponse("Invalid header found.") except Exception as e: return HttpResponse(f"Error sending email: {e}") return HttpResponse("Email sent successfully.")Using send_mass_mail Function
Section titled “Using send_mass_mail Function”from django.core.mail import send_mass_mailfrom django.http import HttpResponsefrom django.core.mail import BadHeaderError
def send_email_view(request): datatuple = [ ("Subject 1", "Message 1", "noreply@example.com", ["user@example.com"]), ("Subject 2", "Message 2", "noreply@example.com", ["user@example.com"]), ] try: send_mass_mail(datatuple) except BadHeaderError: return HttpResponse("Invalid header found.") except Exception as e: return HttpResponse(f"Error sending email: {e}") return HttpResponse("Email sent successfully.")Using mail_admins Function
Section titled “Using mail_admins Function”# settings.py
ADMINS = [("Admin", "admin@example.com")]from django.core.mail import mail_adminsfrom django.http import HttpResponsefrom django.core.mail import BadHeaderError
def send_email_view(request): subject = "Admin Notification" message = "This is a notification email for admins." try: mail_admins(subject, message) except BadHeaderError: return HttpResponse("Invalid header found.") except Exception as e: return HttpResponse(f"Error sending email: {e}") return HttpResponse("Email sent to admins successfully.")Using EmailMessage Class
Section titled “Using EmailMessage Class”from django.core.mail import EmailMessagefrom django.http import HttpResponsefrom django.core.mail import BadHeaderError
def send_email_view(request): # EmailMessage arguments: subject, body, from_email, recipient_list email = EmailMessage( "Custom Email", "This is a custom email with attachments.", "noreply@example.com", ["user@example.com"], ) # absolute path to the file you want to attach email.attach_file("/path/to/attachment.pdf") try: email.send() except BadHeaderError: return HttpResponse("Invalid header found.") except Exception as e: return HttpResponse(f"Error sending email: {e}") return HttpResponse("Custom email sent successfully.")Django Email Templates
Section titled “Django Email Templates”Generally, it’s a good practice to use email templates when sending emails in Django. This allows you to separate the email content from your views and makes it easier to manage and update your email content.
Using Django Templated Mail
Section titled “Using Django Templated Mail”-
Install
Terminal window uv add django-templated-mail -
Create an html template in
templates/emailsdirectory, for examplewelcome_email.html:{% block subject %}Welcome to MySite!{% endblock %}{% block text_body %}{% comment %}This contains text content{% endcomment %}Thank you for visiting our site. We're excited to have you on board.{% endblock %}{% block html_body %}{% comment %}This contains HTML content{% endcomment %}<h1>Welcome to MySite, {{ name }}!</h1><p>Thank you for visiting our site. We're excited to have you on board.</p>{% endblock %} -
Use the
BaseEmailMessageclass in your view to send the email:from templated_mail.mail import BaseEmailMessagefrom django.http import HttpResponsefrom django.core.mail import BadHeaderErrordef send_email_view(request):email = BaseEmailMessage(template_name="emails/welcome_email.html",context={"name": "John Doe"},)try:email.send(["user@example.com"], # list of recipient email addressesfrom_email="support@example.com",)except BadHeaderError:return HttpResponse("Invalid header found.")except Exception as e:return HttpResponse(f"Error sending email: {e}")return HttpResponse("Templated email sent successfully.")
If you do not pass from_email, BaseEmailMessage falls back to DEFAULT_FROM_EMAIL.
Using Django’s Built-in Template Rendering
Section titled “Using Django’s Built-in Template Rendering”If you want a simpler and more explicit approach, you can render the email body with Django’s template loader and send it with EmailMultiAlternatives.
from django.core.mail import EmailMultiAlternativesfrom django.template.loader import render_to_stringfrom django.utils.html import strip_tags
def send_email_view(request): context = {"name": "John Doe"} subject = render_to_string("emails/welcome/subject.txt", context).strip() html_body = render_to_string("emails/welcome/body.html", context) text_body = strip_tags(html_body)
email = EmailMultiAlternatives( subject=subject, body=text_body, from_email="support@example.com", to=["user@example.com"], ) email.attach_alternative(html_body, "text/html") email.send()This pattern is useful when you want full control over the sender, subject, and both text and HTML bodies without relying on a helper package.