Mail Merge uses a template to send similar emails to multiple recipients while keeping the content personalized.
Why is this important? Well, you can simply copy and paste and replace the content and then send the emails, but what happens when you have 300 recipients? Copy and paste don’t seem so fun anymore. Using a mail merge template with Python is the way to go for high-volume sends.
Before we jump into the code, let’s see how our application works. However, for that, we need an essential step, which is creating a .csv file containing all the emails and information we will use.
The file will look like this, and you can choose how you name it:
Keep in mind that you can add whatever you like here or you can even delete columns. The only ones that are “enforced” are Name and Email.
This is how our application will look:
Here, we can fill in the subject, and the body and select the .csv file that we had created.
If we don’t specify all the fields, we will get an error message.
The interesting part here is how we define the subject and the body.
Here, {Name}, {Account}, {Address} and {Gift} will be replaced by the values stored on the .csv file. So each recipient will get a personalized email. Remember that the values used between brackets need to match the names in the .csv file.
Let’s click Submit and see what happens.
We have successfully sent emails to all recipients. Let’s check their inbox.
As we can see, all recipients received a personalized email, as all the fields were replaced accordingly.
Installing the Flask package
As we want to create a Flask web application, our best option is to use Flask, one of the most popular Micro Frameworks in the Python world:
$ pip3 install Flask
$ pip3 install Flask-session
Once installed, we’re ready to go:
Creating the Mail Merge with Python project
First, we’re going to create a folder called MailMerge, and inside we’re going to create another folder called templates.
Let’s create a file called MailMerge.py in the MailMerge folder, and add the following code:
# Load your env variables
from dotenv import load_dotenv
load_dotenv()
# Import your dependencies
from flask import Flask,render_template,json,request,flash,redirect,url_for,session
from flask_session.__init__ import Session
import os
import csv
import re
from nylas import APIClient
# Create the app
app = Flask(__name__)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)
# Initialize your Nylas API client
nylas = APIClient(
os.environ.get("CLIENT_ID"),
os.environ.get("CLIENT_SECRET"),
os.environ.get("ACCESS_TOKEN")
)
# This the landing page
@app.route("/", methods=['GET','POST'])
def index():
# We're using a GET, displat landing page
if request.method == 'GET':
return render_template('main.html')
# # Get parameters from form
else:
subject = request.form["subject"]
body = request.form["body"]
mergefile = request.form["mergefile"]
# Session variables
session["subject"] = subject
session["body"] = body
# Make sure all fields are filled
if not subject or not body or not mergefile:
flash('You must specify all fields')
return redirect(url_for('index'))
else:
session["subject"] = None
session["body"] = None
# Auxiliary variables
email = ""
emails = []
row_header = {}
i = 0
subject_replaced = subject
body_replaced = body
# Open the CSV file
file = open(mergefile)
# Read the CSV contents
mergemail_file = csv.reader(file)
# Read and save the headers
headers = []
headers = next(mergemail_file)
for header in headers:
row_header[header] = i
i += 1
# Read all rows of the CSV file
for row in mergemail_file:
# Assign parameters to auxiliary variables
subject_replaced = subject
body_replaced = body
# Read all headers
for header in headers:
# Search for header and replace them with
# the content on the CSV file
if re.search("{"+f"{header}"+"}", subject):
subject_replaced = re.sub("{"+f"{header}"+"}", row[row_header[f"{header}"]],
subject_replaced)
if re.search("{"+f"{header}"+"}", body):
body_replaced = re.sub("{"+f"{header}"+"}", row[row_header[f"{header}"]],
body_replaced)
#Try to get the Name and Last_Name
try:
full_name = row[row_header["Name"]] + row[row_header["Last_Name"]]
except:
full_name = row[row_header["Name"]]
# Try to send an email
try:
# Create the draft
draft = nylas.drafts.create()
# Add the subject
draft.subject = subject_replaced
# Add the body
draft.body = body_replaced
# Add the recipient and email
draft.to = [{"name":full_name,"email":row[row_header["Email"]]}]
# Send the email
draft.send()
# It was successful, added to the emails array
email = row[row_header["Email"]]
emails.append(email)
except:
# There's a problem
print("Something went wrong")
# Call the results page
return redirect(url_for('results', emails = emails))
# Show recipients emails
@app.route("/results", methods=['GET'])
def results():
# Get the list of emails
emails = request.args.getlist('emails')
# Call the results page passing emails as parameters
return render_template('results.html', emails = emails)
# Run our application
if __name__ == "__main__":
app.run()
Inside the templates folder, we need to create 3 different files, let’s start with base.html:
{% extends 'base.html' %}
{% block content %}
<div class="bg-green-300 border-green-600 border-b p-4 m-4 rounded w-2/5 grid place-items-center">
<h1 class="text-3xl"> The email was sent to the following addresses</h1>
<br>
{% for email in emails: %}
<p class="font-semibold">{{ email }}</p>
{% endfor %}
</div>
<div class="bg-green-300 border-green-600 border-b p-4 m-4 rounded w-2/5 grid place-items-center">
<a href="/" class="text-blue-600">Go back</a>
</div>
{% endblock %}
And that’s it. We’re ready to roll.
Running our Mail Merge application
In order to run our application, we just need to type the following on the terminal window:
$ python MailMerge.py
Our Mail Merge Template with Python and Flask application will be running on port 5000 of localhost, so we just need to open our favourite browser and go to the following address:
http://localhost:5000
If you want to learn more about our Email APIs, please go to our documentation Email API Overview.