Introduction
Sending emails is one of the most common task in any web application. Be it while signing up, password reset, notifications, payment related, and much more - sending email has become a mandatory aspect. In the past in my Django applications, I used Gmail to send emails.
For the SaaS product I'm building I decided to use a comprehensive tool to send transaction emails, as there is quite a lot of email sending functionality built as part of the product. On exploring tools like Brevo, Mailchimp, Hubspot, Zoho, Convertkit, I finally decided to go ahead with MailerSend.
Sharing the steps that need to be configured so that it'll be helpful for anyone setting up transactional emails in your Django application.
Install Django & Create a project
Let's perform the usual steps of creating a virtual environment, followed by installing Django, and creating a project.
py -m venv venv
venv\Scripts\activate
pip install Django
django-admin startproject djangoandmailersend
cd djangoandmailersend
Start the development server to ensure the initial steps bring up the default page.
python manage.py runserver
Boom ๐ฅ
Build a simple flow
What's the fun without a use case, isn't it? Let's add a plain html that has an input box for the user to enter an email address and click on a button "Surprise me!". The user should receive an email with an inspirational quote.
Let's first write the required skeleton code except for the email sending and fetching a quote.
Add a folder called
templates
underdjangoandmailersend
folder.In the newly created folder add a file and name it
home.html
Navigate to
settings.py
and add the path to fetch the templates againstDIRS
property like ๐import os ... ... TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [os.path.join(BASE_DIR, "djangoandmailersend", "templates")], "APP_DIRS": True, "OPTIONS": { "context_processors": [ "django.template.context_processors.debug", "django.template.context_processors.request", "django.contrib.auth.context_processors.auth", "django.contrib.messages.context_processors.messages", ], }, }, ]
Create a file
views.py
at the same level asurls.py
.Add the following method to the newly added
views.py
def send_motivational_quote(request): return render(request, "home.html", {"message": "Check your email to feel inspired"})
Add the following to
home.html
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Django and MailerSend</title> <style> body { display: flex; flex-direction: column; justify-content: center; align-items: center; min-height: 100vh; margin: 0; } .form-container { text-align: center; } .text-input { padding: 10px; width: 300px; font-size: 16px; margin-bottom: 20px; border: 1px solid #ccc; border-radius: 5px; } .submit-button { padding: 10px 20px; font-size: 18px; background-color: #fb8500; color: #fff; border: none; border-radius: 5px; cursor: pointer; } .message { font-size: 16px; margin-top: 20px; color: #fb8500; } </style> </head> <body> <div class="form-container"> <h2>I'd like to receive a motivational quote!</h2> <form action="{% url 'send-email' %}" method="post"> {% csrf_token %} <input type="text" class="text-input" name="textbox_name" placeholder="Enter email here"> <br> <button type="submit" class="submit-button">Surprise me!</button> <br> <p class="message">{{ message }}</p> </form> </div> </body> </html>
- ๐กIn order to keep things simple, I added
views.py
in the main project itself. Likewise, I added CSS styles in the HTML file itself. In a real environment, this is not advised.
On refreshing the page now, this is how it should look like:
Cool, isn't it? ๐
Implement the Motivational quote logic
Let's use the free API from API Ninjas. As a first step, sign up with API Ninjas.
On successful signup, login to your API Ninjas account. On the dashboard page, you should see your API Key. Copy the same.
Let's come back to our workspace. In order to store the API Key, it is good practice to store them in a .env
file and access it using the environ's get method.
Create a file under djangoandmailersend
folder and name it .env
. Add a property as below:
API_NINJAS_API_KEY=<YOUR-API-KEY-HERE>
We'll write a method that invokes an API from API Ninjas that will return a JSON
object with a quote, author and the category of the quote.
from dotenv import load_dotenv
import os
import requests
load_dotenv()
def fetch_motivational_quote():
""" Invokes API Ninja's API to fetch an inspirational quote
"""
category = 'inspirational'
api_url = 'https://api.api-ninjas.com/v1/quotes?category={}'.format(category)
API_KEY = os.environ.get('API_NINJAS_API_KEY')
response = requests.get(api_url, headers={'X-Api-Key': API_KEY})
if response.status_code == requests.codes.ok:
print(response.text)
else:
print("Error:", response.status_code, response.text)
def send_motivational_quote(request):
fetch_motivational_quote()
return render(request, "home.html", \
{"message" : "Check your email to feel inspired!"})
Set up MailerSend related properties
Now that we have completed a standalone method to fetch an inspirational quote, let's now focus on setting up and configuring MailerSend.
Sign up with MailerSend as the first step. In order to use MailerSend for transactional emails, one should have a domain and that needs to be verified. There is a detailed article on their website that explains step by step.
Once done, make sure to activate your account. This will require a clear explanation about the purpose of sending transactional emails, the user's background on running the associated business. In short, one needs to prove their credibility for the account to be activated.
Once the initial setup steps are complete, navigate to Integrations on the left pane. You should see a panel to manage your API Tokens.
Here is a detailed article on managing API tokens.
Alright, we completed all the steps from MailerSend end. Now let's head back to our workspace. Navigate to the .env file and add the following ๐
DEFAULT_FROM_EMAIL=<YOUR-EMAIL-ID-FROM-THE-VERIFIED-DOMAIN>
MAILERSEND_API_TOKEN=<YOUR-MAILERSEND-API-TOKEN>
Next, let's configure email related properties in our settings.py
. Prior to which, we should install Anymail from PyPi
pip install "django-anymail[mailersend]"
Make sure to add it in under INSTALLED_PACKAGES
in settings.py
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"anymail",
]
Next, we add a couple of properties towards the end of settings.py
# MailerSend
ANYMAIL = {
'MAILERSEND_API_TOKEN': os.environ.get("MAILERSEND_API_TOKEN"),
"MAILERSEND_SENDER_DOMAIN": '<YOUR-VERIFIED-DOMAIN>'
}
EMAIL_BACKEND = "anymail.backends.mailersend.EmailBackend"
# The id used for sending emails
DEFAULT_FROM_EMAIL = os.environ.get("DEFAULT_FROM_EMAIL")
settings.py ๐
from dotenv import load_dotenv
from pathlib import Path
import os
load_dotenv()
If you miss this, the properties from our .env
file will not be loaded.
Write code to send email
Now that all properties related to MailerSend are set, let's work on the actual email sending code. In order to do that, let's modify the method in views.py
Update the existing send_motivational_quote
as below ๐
from django.core.mail import send_mail
from django.shortcuts import render
from django.template.loader import render_to_string
from dotenv import load_dotenv
import json
import os
import requests
from django.conf import settings
load_dotenv()
def send_motivational_quote(request):
if request.method == "POST":
email = request.POST.get("email") # Extract email from form data
response_code, response_text = fetch_motivational_quote()
# Parse the JSON string into a Python object
try:
response_text = json.loads(response_text)
except json.JSONDecodeError:
# Handle the exception if the response is not a valid JSON string
message = "Sorry, something went wrong. Please try again."
return render(request, "home.html", {"message": message})
# Extracting quote and author
quote_text = response_text[0]['quote']
quote_author = response_text[0]['author']
if response_code != 200:
message = "Sorry, something went wrong. Please try again."
return render(request, "home.html", {"message": message})
else:
subject = "Your daily dose of inspiration"
from_email = settings.DEFAULT_FROM_EMAIL
to_email = email
body = render_to_string('email_template.html',
{'quote_text': quote_text, 'quote_author': quote_author})
send_mail(subject, body, from_email, [to_email], html_message=body)
message = "Check your email to feel inspired!"
else:
message = ""
return render(request, "home.html", {"message": message})
def fetch_motivational_quote():
""" Invokes API Ninja's API to fetch an inspirational quote
"""
category = 'inspirational'
api_url = 'https://api.api-ninjas.com/v1/quotes?category={}'.format(category)
API_NINJAS_API_KEY = os.environ.get('API_NINJAS_API_KEY')
response = requests.get(api_url, headers={'X-Api-Key': API_NINJAS_API_KEY})
return response.status_code, response.text
Let's look the the methods in detail.
The method fetch_motivational_quote
fetches a quote from APINinjas using requests by passing the url and the API_KEY. I selected the category as inspirational. Check here for the complete list of options.
The method send_motivational_quote
does the following:
Checks whether the request method is POST
If yes, fetch the value of email from the form
Invoke the
fetch_motivational_quote
to fetch the response code and response textParse the JSON String to a Python object
Extract the quote and author
Set appropriate values for subject, body, from and to emails
Finally invoke Django's
send_mail
method by passing these valuesReturn the home page with a success message
Let's now add a html for the email_template so that it looks neat ๐คฉ. Create a file email_template.html
under the folder djangoandmailersend\templates.
Add the following code, again nothing fancy here ๐
<!DOCTYPE html>
<html>
<head>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
color: #333;
line-height: 1.6;
}
.container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
background: #fff;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
.header {
text-align: center;
color: #444;
}
.quote {
font-style: italic;
color: #555;
padding: 20px;
border-left: 3px solid #007bff;
}
.author {
text-align: right;
color: #555;
padding: 10px;
}
.footer {
text-align: center;
margin-top: 20px;
color: #666;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Your Daily Dose of Inspiration</h1>
</div>
<div class="quote">
"{{ quote_text }}"
</div>
<div class="author">
- {{ quote_author }}
</div>
<div class="footer">
<p>Stay inspired!</p>
</div>
</div>
</body>
</html>
Time to see it work โบ
I gave my email id in the home page, and I received an email. Woohoo ๐
Conclusion
In this post, we saw how to integrate Django and MailerSend. The key point in order to use a product like MailerSend is that one needs to own and verify a domain and ensure they use it to send appropriate transactional or marketing emails only.
Since I use MailerSend to send transactional emails in Wobu, I ensured all the setup steps are complete.
Here is my GitHub link if you are interested to take a look at the complete code.