DEV Community

Cover image for How to send email with Django: Complete SMTP guide
David Ozokoye
David Ozokoye

Posted on • Originally published at sendlayer.com

How to send email with Django: Complete SMTP guide

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, I'll show you different ways to send emails with Django.

Table of contents

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 email system overview

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 backends Django supports, you can build a custom email backend for your project. However, I'll show you how to use the built-in SMTP Email Backend to send emails in 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.

Start your free trial at SendLayer

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

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'
Enter fullscreen mode Exit fullscreen mode

I'm using SendLayer's SMTP server as the email host, but you can use any other SMTP server you'd like.

Django email settings configuration

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.

Securing your 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. Create a .env file in your project's root directory:

EMAIL_HOST_USER='your-sendlayer-username'
EMAIL_HOST_PASSWORD='your-sendlayer-password'
Enter fullscreen mode Exit fullscreen mode

Start by installing the python-decouple library:

pip install python-decouple
Enter fullscreen mode Exit fullscreen mode

Once the installation completes, import and use it in your settings.py:

from decouple import config

# other code snippet...

EMAIL_HOST_USER = config('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD')
Enter fullscreen mode Exit fullscreen mode

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's particularly useful for welcome emails, password reset emails, and notification emails from contact forms.

To use this function, you'll need to specify 4 required parameters:

  • subject: The email subject line
  • message: The body text of the email
  • from_email: The sender's email address
  • recipient_list: A list of recipient email address(es)
    There are other optional parameters you can add:

  • fail_silently: A boolean parameter that determines error handling

    • False: Raises exceptions if there's an error
    • True: Suppresses errors during sending
  • connection: An optional email backend to use instead of the default

  • html_message: Optionally specify an HTML content type

Here's 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='paulie@example.com',
    recipient_list=['user@example.com'],
    fail_silently=False,
)
Enter fullscreen mode Exit fullscreen mode

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's SMTP server, the from email address should be from the sending domain you authorized. So if you verified example.com, your from email address should include @example.com.

Send email to multiple recipients

You can send emails to multiple recipients by adding their email addresses to the recipient_list parameter, separated by commas:

from django.core.mail import send_mail

send_mail(
    subject='Welcome to Our App',
    message='Thank you for signing up!',
    from_email='paulie@example.com',
    recipient_list=['user1@example.com', 'user2@example.com', 'user3@example.com'],
    fail_silently=False,
)
Enter fullscreen mode Exit fullscreen mode

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.

EmailMessage vs send_mail function

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 send_mail(): subject, body, from_email, and recipient_email.

It also accepts additional optional parameters:

bcc: A list or tuple of addresses used in the "Bcc" header
connection: An email backend instance for using the same connection for multiple messages
attachments: A list of attachments (MIMEBase instances or filename/content/mimetype triples)
headers: A dictionary of extra headers
cc: A list or tuple of recipient addresses for the "Cc" header
reply_to: A list or tuple of recipient addresses for the "Reply-To" header

Here's 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",
    "from@example.com",
    ["recipient@example.com"],
    ["bcc@example.com"],
    reply_to=["paulie@example.com"],
    headers={"Message-ID": "foo"},
)

email.send()
Enter fullscreen mode Exit fullscreen mode

In the snippet above, I've initialized the EmailMessage class and specified the required and optional parameters. Calling the send() method will trigger the connection to the mail server.

Sending emails with attachments

The EmailMessage class accepts methods like attach() and attach_file() that 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:

email.attach_file('path/to/file.pdf', 'application/pdf')
Enter fullscreen mode Exit fullscreen mode

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

def send_report_email():
    email = EmailMessage(
        subject='Your Monthly Report',
        body='Please find your monthly report attached.',
        from_email='paulie@example.com',
        to=['recipient@example.com'],
    )

    # Attach file from memory
    with open('path/to/report.pdf', 'rb') as f:
        email.attach('report.pdf', f.read(), 'application/pdf')

    email.send()
Enter fullscreen mode Exit fullscreen mode

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 be included if you've configured it properly.

Send email with Django including attachments

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:

from django.core.mail import EmailMessage
from django.template.loader import render_to_string

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'
    })

    email = EmailMessage(
        subject=subject,
        body=html_message,
        from_email='noreply@yourplatform.com',
        to=[user_email],
    )
    email.content_subtype = 'html'  # This tells Django to send HTML email
    email.send()
Enter fullscreen mode Exit fullscreen mode

In the code above, I've imported render_to_string, which renders a template into a string. We use this method to load the HTML template from 'templates/welcome.html'.

After adding the snippet, you'll need to create the actual HTML template:

<!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>
Enter fullscreen mode Exit fullscreen mode

This is a simple HTML template to welcome users who sign up to your app. 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: send_mass_mail(). 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's the format:

(subject, body, from_email, recipient_list)
Enter fullscreen mode Exit fullscreen mode

Each message must have the format specified above. Here's an example usage:

from django.core.mail import send_mass_mail

message1 = (
    "Welcome to SendLayer",
    "This is a test bulk email sent through Django using SendLayer SMTP server",
    "paulie@example.com",
    ["user1@example.com", "other@example.com"]
)

message2 = (
    "Welcome to SendLayer",
    "This is a test bulk email sent through Django using SendLayer SMTP server",
    "paulie@example.com",
    ["user@example.com"]
)

send_mass_mail((message1, message2), fail_silently=False)
Enter fullscreen mode Exit fullscreen mode

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. For this example, I'll add the email function to a views.py file.

Creating email function in views.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

def sl_send_email(request):
    try:
        send_mail(
            subject='Test Email',
            message='This is a test email from Django using SendLayer SMTP',
            from_email='paulie@example.com',
            recipient_list=['david@example.com'],
            fail_silently=False,
        )
        return HttpResponse("Email sent successfully!")
    except Exception as e:
        return HttpResponse(f"Failed to send email: {str(e)}")
Enter fullscreen mode Exit fullscreen mode

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.

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.

Import the view you just created:

# urls.py
from .views import sl_send_email
Enter fullscreen mode Exit fullscreen mode

Then, add the view to the urlpatterns variable:

from django.urls import path
from .views import sl_send_email

urlpatterns = [
    path('', sl_send_email, name='Send Email'),
]
Enter fullscreen mode Exit fullscreen mode

urlpatterns is Django's default way of specifying the URLs for your views. It's essentially a list containing multiple path() functions.

The path function accepts 3 parameters:

  • Route: A string containing the absolute path to the view. For example, using "email/" will render the view at example.com/email/ on a live site or localhost:8000/email/ on a dev environment.
  • View: Where you specify the view you'd like to display. In our example, this is the sl_send_email view.
  • Name: An optional parameter that makes it easy to reference views in templates and other parts of the application. After adding the snippet, save your changes and start the development server:
python manage.py runserver
Enter fullscreen mode Exit fullscreen mode

Once the server is up, navigate to the route for the function-based view you created. 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.

Test email delivered successfully

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

Console Response of Email Delivery Status

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

Sending a Test Email in Django

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'
Enter fullscreen mode Exit fullscreen mode

This error indicates that you haven't installed the Django package on your machine. To fix it, run:

pip install django
Enter fullscreen mode Exit fullscreen mode

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.')
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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, double-check that the file path in your code is correct.

Frequently asked questions

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 in your Django app as well since it's built on Python.

Wrapping Up

In this comprehensive tutorial, we've explored multiple ways to send emails in Django.

Have questions or want to share your implementation? Drop a comment below. I'd love to hear how you're handling email in your Django projects!

Ready to implement this in your application? Start your free trial at SendLayer and send your first email in minutes.

Top comments (0)