Sending Emails with Django - Setting Up

There are two things to know about when it comes to sending emails with Django. The first is the The Email Backend configuration that tells Django what to do whenever an app within your project tries to send an email, and the other is the actual code of functions and classes that you can use to send the email(s).

In this post I will only explain the first part and show the methods and services you can use for different cases.

You should have two setups for sending emails in your project. One for the Development environment, so that you can easily test the functionality of your site, and the other for the Production environment (live site). I'll show you different options to setup both.

Development Environment

There are 5 Email Backends defined in Django's documentaion that are suitable for development, and can be set with just a couple lines of code:

File Based Backend

Probably the most desirable option for the Development environment is to have the emails sent to text files in one folder of your site.

In your settings.py file:

if DEBUG:
    EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
    EMAIL_FILE_PATH = os.path.join(BASE_DIR, "sent_emails")
  • In the first line we check if DEBUG is set to True, as we don't want to use this in live site, where DEBUG should be false!
  • In the second, we tell Django we want to use the File based option.
  • In third, we define the path to the folder where we want to create and store the output of each email.

In this case Django will create a 'sent_email' folder in the root directory of your project and create a .txt file with the output of an email, for each email sent from your project.

Make sure you have import os, DEBUG = True and BASE_DIR defined in your settings.py file. These get automatically created when you create your project using the startproject command.

Console Backend

With this Backend Django will output the contents of the email in the console from where Django's server is running.

In your settings.py file:

if DEBUG:
    EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

In-memory Backend

This Backend will store the output of the email in the 'outbox' attribute of django.core.mail. The attribute is only created when this backend is used.

This is usually used for running tests. You can read more about it in the Email Services section of the docs.

In your settings.py file:

if DEBUG:
    EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

Dummy Backend

This Backend will basically tell Django to not do anything when an app tries to send an email.

In your settings.py file:

if DEBUG:
    EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend'

Python's SMTP server

There is also a way to use Python's built-in SMTP server to output email content to the console, which essentially gives the same result as the what the Console option does. You can read about that in the docs, if that's what you want.

Production Environment

Once your site is in the production environment, you need to be using a different settings file that imports settings.py file in it. All the settings mentioned below should go in that file.

The first thing you need to do is to set two values in your production settings file, which are:

DEFAULT_FROM_EMAIL = '[email protected]'
SERVER_EMAIL = '[email protected]'

DEFAULT_FROM_EMAIL is the email address that Django uses for the 'From' header in emails if it is not specified in the function that send the email. For example, if you are using Django's Authentication system, Django will use this value when it sends emails related to the registration process. The Default value of DEFAULT_FROM_EMAIL is '[email protected]', which is probably not what you want your users to see.

Similarly, SERVER_EMAIL sets the default 'From' header of error message emails sent to Admins and Managers, if you have that set up.

Now, to actually send the emails to other people's inboxes, you would need to signup with an Email Delivery provider and obtain an SMTP username and password. There are few providers that have a basic plan which lets you send emails for free. I will discuss a couple.

Gmail

You can actually use your gmail username and password as SMTP username and password and it will work but with some drawbacks, which I'll discuss in a second.

But to try this method: In your production settings file, make sure DEBUG is set to False, then add:

EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST='smtp.gmail.com'
EMAIL_PORT=587
EMAIL_HOST_USER='[email protected]'
EMAIL_HOST_PASSWORD='your_gmail_password'
EMAIL_USE_TLS=True

Now this will send your emails successfully from your Django project, but there are a couple of problems. First, Google will show your gmail account in the headers of the email by overwriting the 'From' part of your emails. Second, sending a lot of emails in a short period of time could get your account blocked.

So this method is obviously not a good option but you can still use it if you just want to test your production environment, or if you are debugging, and hence that's why I've included it in here instead of moving on to a more robust option.

Moving on, there are many services that you can use for reliably sending emails from Django. Those include Google's G Suite, Amazon SES, SendGrid and MailGun. Some have free plans and others have only paid ones. The one that I'm going to discuss has a really good free plan, and is really easy to setup and is called SparkPost.

SparkPost

Go to SparkPost's website and create a Free account to get started.

During the account creation you will be asked for your Sending domain. Enter in the domain from where you want to send the emails:

SparkPost - Enter Domain

Then select SMTP:

SparkPost - Select SMTP

Note down and store the generated password as you will need it later:

SparkPost - SMTP Relay Info

Inside your SparkPost dashboard, you will now need to verify your ownership of the domain name.

  • Go to Account > Sending Domains, find the sending domain that you entered and click 'Settings' under DKIM Record.
  • You will then need to enter the TXT record in your Domain Name Registrar's settings.

After some time, you should be able to click 'Test' and successfully verify the domain.

Now, there are two ways to configure this in your Django Project. If you look at their documentation page called Using SparkPost with Django you will see that we can either use their Python client library or use the standard SMTP backend. Let's see how to do both.

Option 1: Using Python library.

Install library using pip:

$ pip install sparkpost

Then in your settings file:

SPARKPOST_API_KEY = 'API_KEY'
EMAIL_BACKEND = 'sparkpost.django.email_backend.SparkPostEmailBackend'

Replace API KEY with the password that was shown for the SMTP Relay. There are also some options including the ones for tracking that you might want to change, so do read their documentation.

Option 2: Using standard SMTP Relay

In your settings file, add:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.sparkpostmail.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'SMTP_Injection'
EMAIL_HOST_PASSWORD = 'API_KEY'
EMAIL_USE_TLS = True

Replace API KEY with the password for the SMTP relay.

The emails should now be working from your website; however, there are still a couple of things we need to do.

Using Environment Variables

You should always avoid having sensitive information such as API keys and passwords directly inside your source code. This can be done in different ways and with different setups, but I will show you how to do that by using Environment Variables.

You will need to find and edit your WSGI file from your web host's Dashboard. In case you are using PythonAnywhere, you can go to the 'Web' tab and edit your WSGI file to add this:

os.environ["EMAIL_KEY"] = "Your API Key"

And for specifically PythonAnywhere you will also have to add this in your post_activate file. Under the 'Files' tab, go to virtualenvs > 'yourvenn' > bin, and edit postactivate by adding:

export EMAIL_KEY="Your API Key"

Then finally in your settings file, you can replace the old code with the new that uses the environment variable:

For Option 1:

# Replace this:
SPARKPOST_API_KEY = 'API_KEY'

# With this:
SPARKPOST_API_KEY = get_env_variable("EMAIL_KEY")

For Option 2:

# Replace this:
EMAIL_HOST_PASSWORD = 'API_KEY'

# With this:
EMAIL_HOST_PASSWORD = get_env_variable("EMAIL_KEY")

This way the key will only be defined in the web host's config, and you can safely share your code or put it in a public repository, if you wish.

Also, I've only made the key into an environment variable, but you can store other information that you consider sensitive the same way. You can read more about Environment Variables with PythonAnywhere on their help page.

One final step

Hopefully, now you are able to send the emails, which is great, except that if you look at the email headers, you will find something similar to 'mailed-by: sparkpostmail1.com'. In order to change this you will need to set a Bounce Domain.

  • In your SparkPost dashboard, go to Account > Sending Domain, and add another domain and verify it. For example, you can have mail.yourdomain.com.
  • Once it is verified, Go to Account > Bounce Domains, and add the same domain and verify it.

You should now see this domain in the mailed-by header of your emails.

Note: Make sure that when you are verifying your Bounce Domain from your DNS manager, you only target DNS requests and not Http. So if you are using CloudFlare for instance, make sure the cloud next to the record is grey instead of orange.

Closing remarks

If you are having any issues with configuring SparkPost or any other service, you can use a really good Django library called Django Anymail. They take care of all the settings associated with the service, and only require the service name and the keys in the settings.

Hopefully, you are now able to send emails from your Django website.

Share your thoughts or questions in the comment section and thank you for reading!

blog comments powered by Disqus