Have you ever struggled with setting up email integration in your Django projects? Whether it’s configuring SMTP settings, handling security concerns, or automating contact forms, email functionality is crucial for user engagement and trust.
In this tutorial, we’ll walk through how to send emails using Django with practical, step-by-step instructions. We’ll cover how to configure Django SMTP connections, how to set up an password for your email provider, and how to send emails through the Django shell. We’ll also look at how to set up a contact form for your Django app, which will allow your customers to contact you.
Most web applications use email to manage crucial operations, such as resetting passwords, account activation, receiving customer feedback, sending newsletters, and marketing campaigns. While Gmail works for testing or small projects, production websites should use dedicated email services such as AWS SES, SendGrid, or Mailgun.
However, if you compare the cost and the effort of using a dedicated email service, sending emails with your personal email can be more reasonable for small or testing projects. So we’ll take that approach here to keep things simple.
Note: It’s not a good idea to use your personal email service for your production website. You can learn more about Gmail sending restrictions, or refer to the limitations of your email provider.
Note: the full code for this tutorial is available on GitHub.
SMTP (or the Simple Mail Transfer Protocol) is a set of rules for determining how emails are transferred from senders to recipients. SMTP servers use this protocol to send and relay outgoing emails. (Note that other protocols govern how emails are received.)
An SMTP server always has a unique address and a specific port for sending messages, which in most cases is 587. We’ll see how the port is relevant in Django email send.
For this example, we’ll use Gmail’s SMTP server, where:
Now, let’s see how we can send email with Django.
Every Django project should have a virtual environment, as we don’t want to mess up the project dependencies. To create one, run the following:
python <span>-m venv .venv</span>
Note: if you’re unfamiliar with virtual environments, make sure to check our Python virtual environments guide.
The command above creates a virtual environment with the name .venv. To activate this virtual environment, you can use the following:
<span># CMD </span>.venv<span>\Scripts\activate </span> <span># Power Shell </span>.venv<span>\Scripts\Activate.ps1 </span> <span># WSL </span><span>source .venv/bin/activate</span>
Since Django is a third-party package, you have to install it with pip:
pip <span>install django</span>
This will install the latest version of Django, which you can check with pip freeze.
To create a Django project, you call the command line utility django-admin:
django-admin startproject EmailProject
With the command above, you’re creating a Django project with the name EmailProject, but you can create the project with whatever name you want. Now, enter to the project directory and run the server:
<span>cd EmailProject </span>python manage.py runserver
After running the Django server, visit http://localhost:8000 in your browser. You’ll see an auto-generated page with the latest Django release notes.
The email backend is the mechanism to send emails with Django. By default, Django uses django.core.mail.backends.smtp.EmailBackend, which allows it to connect to an SMTP server and send emails. Depending on the environment (development or production), you can choose a different email backend to suit your needs.
You’ll need to modify the settings file before sending emails, so let’s locate that file with the below command:
Note: for simplicity’s sake, we’ll be using only UNIX (macOS or Linux) system commands.
python <span>-m venv .venv</span>
The tree command outputs the file structure of a directory. In this case, since we’re not giving it a specific directory path, we’ll get something similar to the following if we’re in the root folder of the project:
<span># CMD </span>.venv<span>\Scripts\activate </span> <span># Power Shell </span>.venv<span>\Scripts\Activate.ps1 </span> <span># WSL </span><span>source .venv/bin/activate</span>
The file we’ll be constantly modifying through this tutorial is the settings.py inside the EmailProject folder. It holds all the project configuration you’ll need, and allows you to set custom variables. As the Django docs say, “A settings file is just a Python module with module-level variables”.
Let’s look at the settings required for sending an email with Django. Open the EmailProject/settings.py file and paste the following settings at the bottom of the file:
pip <span>install django</span>
Let’s break down the code above by analyzing each one of these settings.
The EMAIL_BACKEND setting declares the backend our Django project will use to connect with the SMTP server.
This variable is pointing to the smtp.EmailBackend class that receives all the parameters needed to send an email. I strongly suggest you take a look at the class constructor directly on the Django source code. You’ll be surprised by how readable this code is.
Note: although this class is the default EMAIL_BACKEND, it’s considered a good practice to be explicit in the Django settings.
All the other email settings will be based on the constructor of this EmailBackend class.
The EMAIL_HOST setting refers to the SMTP server domain you’ll be using. This depends on your email provider. Below is a table with the SMTP server host corresponding to three common providers:
We’re leaving this setting blank for now since we’ll use a .env file later to avoid hard-coded sensitive keys or per-site configurations. You should never set credentials directly into the code. We’ll be using Django Environ to solve this problem.
The EMAIL_PORT setting must be set to 587 because it’s the default port for most SMTP servers. This remains true for personal email providers. This port is used along with TLS encryption to ensure the security of email sending.
Transport Layer Security (TLS) is a security protocol used across the Web to encrypt the communication between web apps (Django) and servers (SMTP server).
Originally, we set the EMAIL_USE_TLS variable to True. This means Django will use Transport Layer Security to connect to the SMTP server and send emails. (It’s mandatory for personal email providers.)
The EMAIL_HOST_USER setting is your personal email address. Leave it blank for now, since we’ll use django-environ to set up all of these credentials.
The EMAIL_HOST_PASSWORD setting is the app password you’ll get from your email account — the process we’ll be doing right after this section. Same story: leave this setting blank, as we’ll use environmental variables later.
For other providers, you can adjust the settings accordingly. For example:
Outlook Configuration:
python <span>-m venv .venv</span>
Yahoo Configuration:
<span># CMD </span>.venv<span>\Scripts\activate </span> <span># Power Shell </span>.venv<span>\Scripts\Activate.ps1 </span> <span># WSL </span><span>source .venv/bin/activate</span>
Since “Less Secure Apps” is deprecated by Google, the proper and secure way to connect to Gmail account for sending emails is to use App Passwords. App Passwords are available only if you enable 2-Step Verification for your Google account.
If you’re using other email providers, make sure to read the following guides:
Even if you’re just sending emails in development, you shouldn’t write passwords directly into the source code. This becomes even more important when using a version control system along with GitHub to host your project. You don’t want people to access your data.
Let’s see how we can prevent this by using Django-environ.
Create a .env file inside the EmailProject directory (where the settings.py file is located) with the command below:
python <span>-m venv .venv</span>
Now, open that .env file and enter the following key–value pairs:
<span># CMD </span>.venv<span>\Scripts\activate </span> <span># Power Shell </span>.venv<span>\Scripts\Activate.ps1 </span> <span># WSL </span><span>source .venv/bin/activate</span>
Breaking down the contents of this file:
To make use of these environmental variables, we’ll need to install Django-environ:
pip <span>install django</span>
Note: make sure your virtual environment is activated.
Now, open the settings.py located in the EmailProject directory and use the code below:
django-admin startproject EmailProject
First, we’re importing the environ package at the top of the settings file. Remember that all imports should be at the start. Then we create an env variable which will contain all the key–value pairs available on the .env.
The env(‘KEY’) statement means we’re looking up the value of that key. Before proceeding, make sure you have set up your .env file. Otherwise, if some environmental variable isn’t set, you’ll get a Django ImproperlyConfigured error.
Note: RECIPIENT_ADDRESS is a custom setting that we’ll use to send emails to an address we can access.
Don’t forget to include the .env file in your .gitignore if you’re using Git and GitHub. You can do this just by opening it and adding the following line:
<span>cd EmailProject </span>python manage.py runserver
Finally, we get to the juicy part of the article! It’s time to send your first email to Django.
Open up a terminal, activate the virtual environment, and run:
tree
This will create a shell with all the Django settings already configured for us. Inside that brand-new shell, paste the following code:
├── EmailProject │ ├── asgi.py │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py 1 directory, 6 files
We can also make a one-liner without specifying the arguments:
python <span>-m venv .venv</span>
Let’s break down the code above:
Note how we use the settings object to get the from_email (the email you’re sending emails with) and the recipient_list (the RECIPIENT_ADDRESS custom setting we defined in the .env).
Now, if I check my inbox — as I set the RECIPIENT_ADDRESS environmental variable to my email address — I’ll get the email message sent by Django.
In Django 4.x, asynchronous email sending is supported to improve performance. This is useful for high-traffic websites or when sending bulk emails.
Here’s how you can send an email asynchronously:
<span># CMD </span>.venv<span>\Scripts\activate </span> <span># Power Shell </span>.venv<span>\Scripts\Activate.ps1 </span> <span># WSL </span><span>source .venv/bin/activate</span>
Asynchronous email sending is useful in scenarios like:
Note: While Django supports asynchronous email, for production-scale bulk emails, use a background task queue like Celery or Django-Q for true non-blocking operations.
In this section, we’ll build an automated contact form with Django forms and the built-in send_mail function. We’ll also create a custom function, send(), inside the contact form so it’s easier to implement it in the views.
Let’s start by creating the contact app. Enter the project root directory — where manage.py is located — and run:
pip <span>install django</span>
Then, install it in your INSTALLED_APPS variable inside the EmailProject/settings.py file:
django-admin startproject EmailProject
Before advancing with the contact app, let’s configure the urlpatterns inside of the EmailProject/urls.py file. To do this, import the django.urls.include function and include the contact URLs in the overall project. Don’t worry; we’ll configure the contact URLs later:
<span>cd EmailProject </span>python manage.py runserver
Enter the contact app folder and create a forms.py file. It’s a good practice to define all of your forms inside of a forms.py file, but it isn’t mandatory. That’s why Django doesn’t include this file by default. You can create the forms file with the following commands:
tree
Open the file you just created and make the following imports:
python <span>-m venv .venv</span>
The Django form module gives us all the needed classes and fields to create our contact form. Once again we’re importing the settings object and the send_mail function to send the emails.
Our contact form will contain several fields and use two custom methods: get_info(), which formats the user-provided information, and send(), which will send the email message. Let’s see this implemented in code:
<span># CMD </span>.venv<span>\Scripts\activate </span> <span># Power Shell </span>.venv<span>\Scripts\Activate.ps1 </span> <span># WSL </span><span>source .venv/bin/activate</span>
This class is huge, so let’s break down what we do in each part. Firstly, we define four fields that will be required to send the email message:
Heading into the custom methods, we’re only using the get_info method to format the user’s information and return two variables: subject, which is nothing but the inquiry field, and message, which will be the actual email message sent by Django.
On the other hand, the send() method only gets the formatted info from get_info and sends the message with the send_mail function. Although this section was pretty large, you’ll see how we simplified the contact views by implementing all the sending logic to the ContactForm itself.
Open the contact/views.py file and add the following imports:
pip <span>install django</span>
As you can see, we’re going to use Django generic views, which saves us a ton of time when making simple tasks — for example, when setting up a form with FormView or creating a view that only renders a template with TemplateView.
Also, we’re importing the ContactForm that we built in the previous section and the reverse_lazy function used when working with class-based views. Continuing with the views, let’s write the ContactView:
django-admin startproject EmailProject
As you can see, we’re building a simple FormView using the ContactForm we created. We’re also setting up the template_name and the success_url. We’ll write the HTML template and set up the URLs later.
The form valid method let us send the email using the ContactForm.send() method only if all the fields of the form are valid. This implies that if the user enters invalid input — such as an unformatted email address — the message won’t be sent.
The above form_valid method implementation would be equivalent to the following in a function-based view:
python <span>-m venv .venv</span>
Ending this section, we’re going to write a ContactSucessView, which will show a success message to the user. Since we’ve already imported the TemplateView class, we only need to inherit from it and define the template_name attribute:
<span># CMD </span>.venv<span>\Scripts\activate </span> <span># Power Shell </span>.venv<span>\Scripts\Activate.ps1 </span> <span># WSL </span><span>source .venv/bin/activate</span>
You can check out the views.py file on the GitHub repository if you have any concerns.
It’s time to create the URL patterns of the contact app. Since Django doesn’t give us the urls.py file by default, we’ll need to create it with the following command (make sure to be inside the contact app folder):
pip <span>install django</span>
Open that file and set up the app_name and urlpatterns variables:
django-admin startproject EmailProject
We use path to include the route and its correspondent view to the URL configuration of the app. When we set the app_name variable to ‘contact’, it means the URL namespacing of the app will look like this:
<span>cd EmailProject </span>python manage.py runserver
Note: a namespace is what we call URLs dynamically in Django templates and Views.
You can learn more about the Django URL dispatcher in the official documentation.
Django templates are the preferred way to display data dynamically, using HTML and special tags provided by the Django Template Language.
For this specific app, we’ll be using three templates:
Let’s start by creating the contact’s app template structure (make sure you’re inside the contact app folder):
tree
The commands above create the typical template structure of a reusable Django app — appname/templates/appname — and the tree template files I mentioned before. Here’s what the app file structure should now look like:
├── EmailProject │ ├── asgi.py │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py 1 directory, 6 files
Let’s jump into the content of the base.html template:
<span># EmailProject/settings.py </span> <span># Bottom of the file </span>EMAIL_BACKEND <span>= 'django.core.mail.backends.smtp.EmailBackend' </span>EMAIL_HOST <span>= '' </span>EMAIL_PORT <span>= 587 </span>EMAIL_USE_TLS <span>= True </span>EMAIL_HOST_USER <span>= '' </span>EMAIL_HOST_PASSWORD <span>= '' </span>
As you can see, it’s the simple skeleton of an HTML file that includes links to Bootstrap 5. This allows us to stylize our contact app without using CSS files. The {% block name-of-block %} tag allows us to set up a placeholder that “child templates” will utilize. The use of this tag makes template inheritance an easy task.
Before heading into the forms, you’ll need to install the Django crispy forms package, which allows us to stylize them easily:
EMAIL_HOST <span>= 'smtp-mail.outlook.com' </span>EMAIL_PORT <span>= 587 </span>EMAIL_USE_TLS <span>= True </span>EMAIL_HOST_USER <span>= 'your-email@outlook.com' </span>EMAIL_HOST_PASSWORD <span>= 'your-app-password'</span>
Once again, crispy_forms is a Django app, and we need to include it on the INSTALLED_APPS list:
EMAIL_HOST <span>= 'smtp.mail.yahoo.com' </span>EMAIL_PORT <span>= 587 </span>EMAIL_USE_TLS <span>= True </span>EMAIL_HOST_USER <span>= 'your-email@yahoo.com' </span>EMAIL_HOST_PASSWORD <span>= 'your-app-password'</span>
We use the template pack of Bootstrap 4, because the Bootstrap form classes are compatible between the 4th and 5th version (at the time of writing).
Now, let’s work on the contact.html template:
python <span>-m venv .venv</span>
Note how we extended the base template and make use of the block placeholder. This is what makes Django Template Language so efficient, as it lets us save a lot of HTML copying and pasting.
Talking about the form, we’re using the method “post”, which means that our ContactView will process the data given by the user and send the email if the form is valid. The {% csrf_token %} is mandatory in every form because of security reasons. Django’s documentation has a dedicated page on CSRF tokens and the reasons to use them when working with forms.
We’ll be rendering the form with the crispy template tag, which is why we loaded the crispy tags with {% load crispy_forms_tags %}.
Finally, let’s write the success.html template:
<span># CMD </span>.venv<span>\Scripts\activate </span> <span># Power Shell </span>.venv<span>\Scripts\Activate.ps1 </span> <span># WSL </span><span>source .venv/bin/activate</span>
As you can see, it’s a simple success announcement with a link to the contact form in case the user wants to send another message.
Let’s run the server again and visit http://localhost:8000 (make sure you have the .venv activated and you’re inside the project root folder):
pip <span>install django</span>
The image below shows what the final contact form looks like.
And this is an image of the success message.
And here’s an image of the email in the inbox.
To make your email-sending logic modular and reusable, you can move the email sending function to a helper function:
django-admin startproject EmailProject
You can now call this function wherever you need to send emails, including your contact form.
You can use django.test to test send email Django functionalities.
<span>cd EmailProject </span>python manage.py runserver
HTML emails provide better design and presentation. Use Django’s template engine to create rich email content:
tree
For production-ready applications, consider using third-party services such as SendGrid, Mailgun, or AWS SES. These services offer advanced features like email analytics, delivery tracking, and spam filtering.
├── EmailProject │ ├── asgi.py │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py └── manage.py 1 directory, 6 files
Send email verification links during user registration to prevent spam accounts.
<span># EmailProject/settings.py </span> <span># Bottom of the file </span>EMAIL_BACKEND <span>= 'django.core.mail.backends.smtp.EmailBackend' </span>EMAIL_HOST <span>= '' </span>EMAIL_PORT <span>= 587 </span>EMAIL_USE_TLS <span>= True </span>EMAIL_HOST_USER <span>= '' </span>EMAIL_HOST_PASSWORD <span>= '' </span>
Congrats! You’ve learned how to send emails with Django and how to build a Django contact form as well.
There are many ways to send emails with Django. In this tutorial, you’ve made it with your personal email address, but I’d like you to explore other tools and integrate them into your projects.
In this tutorial, we’ve covered the following:
For more on Django, check out “Build a Photo-sharing App with Django”.
Yes, Django provides a built-in email-sending framework that makes it simple to send emails. By configuring the SMTP settings in your settings.py file, you can send emails using the send_mail function or EmailMessage class.
To configure Django for sending emails:
To send Outlook mail in Django, you can use Django’s email sending functionality with the SMTP settings for Outlook. In your Django project’s settings.py file, configure the SMTP settings for Outlook. These settings will enable Django to connect to the Outlook SMTP server to send emails.
In your Django project’s settings.py, configure your incoming email server settings. You typically need the IMAP (Internet Message Access Protocol) server details for your email provider, along with authentication credentials. Next, use the imaplib library to connect to your email server and retrieve emails. You can do this in your Django views or custom management commands. Once you have fetched an email, you can process it, extract information, and perform any necessary actions within your Django application. This could involve parsing the email content, storing relevant data in your database, or triggering specific actions based on the email’s content or sender.
During development, you can use an optional email backend to test emails without connecting to a real SMTP server. For example: Console Email Backend: Prints email messages to the terminal instead of sending them.
python <span>-m venv .venv</span>
For more advanced testing, use tools like MailHog or Mailtrap, which act as fake SMTP servers for capturing and displaying test emails.
Use Django Environ to load sensitive credentials (like email host, username, and password) from a .env file:
The above is the detailed content of How to Send Email with Django Using SMTP Server. For more information, please follow other related articles on the PHP Chinese website!