Do you want to learn how to send email with Django? When building web applications, one feature that’s often requested is email functionality.
Whether you’re looking to implement a simple email alert for user registrations or contact form notification emails, you’ll need a notification system for your Django web app.
In this post, I’ll explain how Django’s email system works. Then, proceed to show you different ways to send emails with Django.
Understanding Django’s Email System
Django provides a robust email-sending framework through its django.core.mail
module. This module includes functions and classes for sending basic, HTML, and mass emails.
The module requires a backend to function properly. This means you’ll need to configure the email backend you’d like to use for your project.

Django supports many out-of-the-box email backends. The SMTP Backend is the most popular and works well for most applications.
In addition to the default backend Django supports, you can build a custom email backend for your project. I won’t be covering how to implement a custom email backend in Django since it’s beyond the scope of this tutorial.
Instead, I’ll show you how to use the built-in SMTP Email Backend to send emails on your Django application.
How to Send Email With Django
Prerequisites
Before we dive in, make sure you have:
- Django installed in your project (I’m using Django 5.0, but this guide works with Django 3.x and above)
- Basic knowledge of Django and Python
- A working Django project (if you need to create one, check Django’s official documentation)
- An email service provider (I’ll use SendLayer, but the steps are similar regardless of the email provider you choose)
If you’d like to use SendLayer, you can get started with a free account that lets you send up to 200 emails.
After creating your free account, you’ll need to authorize your sending domain. This step is essential to improve email deliverability and verify your account.
Configuring Your Email Backend
As I mentioned earlier, this guide assumes you’re familiar with Django and have a working Django project. I’ll use the default Django email backend for this guide. To proceed, open your project’s settings.py file and add the email configuration below.
# Django email configuration
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.sendlayer.net' # Replace with your SMTP server
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'your-sendlayer-username'
EMAIL_HOST_PASSWORD = 'your-sendlayer-password'
I’m using SendLayer SMTP server as the email host. But you can use any other SMTP server you’d like.

If you’d like to use SendLayer as well, you’ll need to retrieve your SMTP credentials from your SendLayer account. Please see our tutorial to learn how to retrieve your SMTP credentials.
Once you’ve done that, be sure to replace your-sendlayer-username
and your-sendlayer-password
with your actual SMTP credentials.
It’s not advisable to store sensitive details like usernames and passwords in your codebase. I recommend using environment variables to secure sensitive details. For this, create a .env file in your project’s root directory and add your SMTP credentials.
// .env file
EMAIL_HOST_USER = 'your-sendlayer-username'
EMAIL_HOST_PASSWORD = 'your-sendlayer-password'
After that, you’ll need to install a third-party library using the command below:
pip install decouple
Next, return to your settings.py
file and import the config
module from decouple.
from decouple import config
You can use the config
module to reference the email host username and password specified in the .env
file:
EMAIL_HOST_USER = config('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')
Method 1: Send Plain Email Using send_mail() Function
send_mail()
is a built-in function that lets you send simple emails with minimal customizations. It is particularly useful for welcome emails, password reset emails, notification emails from contact forms, etc.
To use this function, you’ll need to specify 4 required parameters:
subject
: The email subject linemessage
: The body text of the emailfrom_email
: The sender’s email addressrecipient_list
: A list of recipient email address(es)
There are other optional parameters you can add to the send_mail()
function before sending your email.
fail_silently
: A boolean parameter that determines error handling.False
: Raises exceptions if there’s an errorTrue
: Suppresses errors during sending
connection
: An optional email backend to use to send your email. This will be used instead of the default email backend in your settings.py file.html_message
: Optionally specify an HTML content type. If specified, it will be used as an alternative to the plain text message.
Here is an example email using the send mail function:
from django.core.mail import send_mail
send_mail(
subject='Welcome to Our App',
message='Thank you for signing up!',
from_email='[email protected]',
recipient_list=['[email protected]'],
fail_silently=False,
)
Be sure to replace the from_email and recipient_list with the sender and recipient’s email addresses.
Pro Tip: If you’re using SendLayer SMTP server, the from email address should be from the sending domain you authorized. So if you verified example.com
, your from email address include @example.com
.
Send Email to Multiple Recipients
You can send the email to multiple recipients. To do so, add the recipient email addresses to the recipient_list parameter. You’ll need to separate each email address with a comma.
from django.core.mail import send_mail
send_mail(
subject='Welcome to Our App',
message='Thank you for signing up!',
from_email='[email protected]',
recipient_list=['[email protected]', '[email protected]', '[email protected]'],
fail_silently=False,
)
Method 2: Send Email With EmailMessage Class
The EmailMessage
class is a built-in module in Django that works similarly to the send_mail()
function. In addition to sending basic emails, this class lets you customize your emails further.

For instance, you can include attachment files, add CC and BCC email addresses, and use a custom HTML template for your emails.
The EmailMessage
class accepts 4 required parameters similar to the send_mail()
function: subject
, body
, from_email
, and recipient_email
.
It also accepts additional optional parameters you can include in the email message. Here are a few optional parameters the EmailMessage class supports:
bcc
: A list or tuple of addresses used in the “Bcc” header when sending the email.connection
: An email backend instance. Use this parameter if you are sending theEmailMessage
viasend()
and you want to use the same connection for multiple messages.attachments
: A list of attachments to put on the message. These can be eitherMIMEBase
instances or(filename, content, mimetype)
triples.headers
: A dictionary of extra headers to put on the message. The keys are the header names, and the values are the header values.cc
: A list or tuple of recipient addresses used in the “Cc” header when sending the email.reply_to
: A list or tuple of recipient addresses used in the “Reply-To” header when sending the email.
Here is a basic example of how to use the EmailMessage class:
from django.core.mail import EmailMessage
email = EmailMessage(
"Email Subject",
"Body of email goes here",
"[email protected]",
["[email protected]", ],
["[email protected]"],
reply_to=["[email protected]"],
headers={"Message-ID": "foo"},
)
In the snippet above, I’ve initialized the EmailMessage class and specified the required and optional parameters. After that, we’ll need to call the send()
method on the EmailMessage
instance we just created above.
email.send()
Calling the send()
method will trigger the connection to the mail server.
Sending Emails With Attachments
The EmailMessage also accepts other methods like the attach()
and attach_file()
. These methods allow you to include attachment files to your emails.
If you use the attach_file()
method, you’ll simply need to enter the complete file attachment path and MIMEType as parameters. Here is an example using the same email instance we created above:
email.attach_file('path/to/file.pdf', 'application/pdf')
You’ll need to replace the attachment path with the path to the file you’d like to attach.
Note: Django handles static and attachment files differently. So you’ll need to properly reference the attachment file in your Python script. See Django’s documentation to learn how.
Here’s another variation using the attach()
method:
from django.core.mail import EmailMessage
import os
def send_report_email():
email = EmailMessage(
subject='Your Monthly Report',
body='Please find your monthly report attached.',
from_email='[email protected]',
to=['[email protected]'],
)
# Attach file from memory
with open('path/to/report.pdf', 'rb') as f:
email.attach('report.pdf', f.read(), 'application/pdf')
email.send()
The attach() method accepts 3 parameters: file name, encoded string, and MIMEType.
We use the with open()
method to access the file and convert it to an encoded string using f.read()
.
When you send a test email, the attachment file should also be sent if you’ve configured it properly.

Sending HTML Emails
Modern emails require HTML syntax for proper formatting and styling. With the EmailMessage class, you can create HTML templates to use as the email message. Here’s how to do it:
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from django.utils.html import strip_tags
def send_welcome_email(user_email):
subject = 'Welcome to Our Platform'
html_message = render_to_string('emails/welcome.html', {
'user_email': user_email,
'site_name': 'Your Platform Name'
})
plain_message = strip_tags(html_message)
email = EmailMessage(
subject=subject,
body=html_message,
from_email='[email protected]',
to=[user_email],
)
email.content_subtype = 'html' # This tells Django to send HTML email
email.send()
In the code above, I’ve added 2 import statements: render_to_string
and strip_tags
. The render_to_string
module renders a template into a string, while strip_tags
removes HTML tags from a string.
We use the render_to_string method to load the HTML template from 'templates/welcome.html'
. After that, we pass a context dictionary with user_email
and site_name
.
After adding the snippet, you’ll need to create the actual HTML template. Django will look for this file in the templates folder specified above. So the HTML email template should sit there.
<!DOCTYPE html>
<html>
<head>
<style>
.email-container {
max-width: 600px;
margin: 0 auto;
font-family: Arial, sans-serif;
}
.button {
background-color: #211FA6;
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
margin: 4px 2px;
cursor: pointer;
border-radius: 10px
}
</style>
</head>
<body>
<div class="email-container">
<h1>Welcome to {{ site_name }}!</h1>
<p>Hello {{ user_email }},</p>
<p>Thank you for joining our platform. We're excited to have you on board!</p>
<a href="https://sendlayer.com/docs/welcome-to-sendlayer/" class="button">Get Started</a>
</div>
</body>
</html>
This is a simple HTML template to welcome users who sign up to your app. I added a little CSS style for the Get Started button.
When you run the script, Django will use the HTML template as the message body when sending the email.
Method 3: Send Bulk Email in Django
If you have a large subscriber list and need to send a newsletter, it can be resource-consuming to use the send_mail()
function. This is because Django will treat each recipient email as a new connection to the mail server.
Fortunately, Django provides a function that simplifies bulk emails, ie, send_mass_email()
. When the function is called, it will treat the emails as a single connection, regardless of the number of emails you’re sending.
It requires one parameter, which is the datatuple containing all individual email messages. Here is the format for the data tuple.
(subject, body, from_email, recipient_list)
Each message must have the format specified above to use this function. Here is an example usage:
from django.core.mail import send_mass_mail
message1 = (
subject="Welcome to SendLayer",
body="This is a test bulk email sent through Django using SendLayer SMTP server",
from_email="[email protected]",
recipient_list=["[email protected]", "[email protected]"]
)
message2 = (
subject="Welcome to SendLayer",
body="This is a test bulk email sent through Django using SendLayer SMTP server",
from_email="[email protected]",
recipient_list=["[email protected]"]
)
send_mass_mail((message1, message2), fail_silently=False)
I set the fail_silently
argument to False
to ensure errors are logged if the email doesn’t deliver to the specified recipients.
How to Send a Test Email in Django
You can add the email function examples I shared in this guide to your views or anywhere else in your Django application. Django has built-in test scripts that enable testing features on your app.
Creating Email Function to View.py
For this example, I’ll add the email function to a views.py
file.
#views.py
from django.http import HttpResponse
from django.core.mail import send_mail
# Create your views here.
def sl_send_email(request):
try:
send_mail(
subject='Test Email',
message='This is a test email from Django using SendLayer SMTP',
from_email='[email protected]',
recipient_list=['[email protected]'],
fail_silently=False,
)
return HttpResponse("Email sent successfully!")
except Exception as e:
return HttpResponse(f"Failed to send email: {str(e)}")
In the snippet above, I’ve created a new function-based view (sl_send_email()
) that accepts a request parameter. Within the function, we’re using the try
except
Python syntax to send the email.
Pro Tip: I used the send_mail()
function for this example. However, it works the same when using the send_mass_mail()
function or EmailMessage
class in Django.
If the email gets delivered, we’ll display “Email sent successfully” on the page. Otherwise, it’ll trigger the except block and render the error message on the page.
I’ve used HttpResponse
to display the page content. However, you can use the render
function in Django to display an HTML template instead.
Adding a Function-Based View to URLs in Django
After creating your function-based view, you’ll need to add the function to a URL endpoint on your app. This can be accomplished in the urls.py file.
Once you’ve opened the urls.py file, import the view you just created using the command below:
#urls.py
from .views import sl_send_email
Then, add the view to the urlpatterns variable on your project.
from django.urls import path
from .views import sl_send_email
urlpatterns = [
path('', sl_send_email, name='Send Email'), # specify path
]
Code breakdown
urlpatterns is Django’s default way of specifying the URLs for your views. It is essentially a list containing multiple path()
functions.
The path function accepts 3 parameters:
- Route: This is a string containing the absolute path to the view. For example, using
"email/"
will render the view in the frontend with the URLexample.com/email/
on a live site orlocalhost:8000/email/
on a dev environment. - View: This is where you specify the view you’d like to display. In our example, this is the
sl_send_email
view. If you used a different name for your function-based view, you’ll need to update the import statement to match yours. - Name: This is an optional parameter that makes it easy to reference views in templates and other parts of the application.
After adding the snippet, be sure to save your changes. Then start up the development server using the command below:
python manage.py runserver
Once the server is up, navigate to the route for the function-based view you created. Doing this will trigger the send_mail()
function and render the HTTP response on the page.
If the email is delivered successfully, you’ll see a success notification on the web page.

Viewing the terminal will also show you the status of the request. A 200
response indicates the request was successful.

You should receive the test email in the inbox of the recipient email(s) you specified in the snippet.

Troubleshooting Common Errors
When testing the code snippets above, I encountered some issues. I’ve highlighted some of the common ones so you won’t have to struggle like I did.
ModuleNotFoundError: No module named 'django'
This error indicates that you haven’t installed the Django package on your machine. To fix it, simply run the command pip install django
in a terminal window.
It could also occur if you activated the wrong virtual environment. You may have installed Django on a separate virtual environment and activated a different one. Simply deactivate the virtual environment and activate the one with Django installed.
Error: (500, b'5.0.0 EMAIL SENDING LIMIT REACHED.')
Most email providers have sending limits on their service. This limit varies depending on the plan you’re subscribed to. If you’ve exceeded your sending limit, you’ll likely encounter this error.
To fix this error, you’ll need to upgrade to a higher plan or switch to a different email provider with higher limits.
Error: [Errno 2] No such file or directory
This error occurs when sending emails with an attachment. It indicates the file path you’ve specified for an email attachment is invalid. To fix this error, be sure to double-check that the file path is correct in your code is correct.
FAQs – Send Email With Django
Below, we’ve answered some of the top questions we see about sending emails in Django.
What is the difference between send_mail() and EmailMessage in Django?
Both the send_mail() function and EmailMessage class are built-in Django modules that let you send emails in your Django app. Their major difference is that EmailMessage allows for more advanced sending options like including attachments or adding BCC addresses.
Can I send emails in Django without SMTP?
Yes! You can use an Email API to route emails from your Django project. In a previous tutorial, we covered how to send emails in Python through an Email API. You can use the code snippets on your Django app as well since it’s built on Python.
Can I schedule emails in Django?
There are several ways to schedule emails in Django. You can use built-in libraries like Django-Q or create a cron job with Django management commands. Additionally, third-party libraries like Celery can help you schedule emails on your app. Here’s an example snippet of how to implement the Celery scheduling.
from celery import shared_task
@shared_task
def send_scheduled_email():
send_mail(
'Subject',
'Message',
'[email protected]',
['[email protected]']
)
That’s it! Now you know different ways to send emails in Django.
Next, would you like to improve the customer experience for new users on your application? Check out our guide on the best welcome email examples for new customers to learn how.