- Products
- Solutions Use casesBy industry
- Developers
- Resources Connect
- Pricing
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.
If you want to learn more, follow our post What is Mail Merge?.
Looking for another SDK? Here are the Ruby, Java and Node versions.
We will use Gmail as our email service provider as setting up is fast and easy.
With the Nylas Email API, we can easily support mail merge. Here’s how:
If you already have the Nylas Python SDK installed and your Python environment configured, continue with the blog.
Otherwise, I recommend reading the post How to Send Emails with the Nylas Python SDK where the basic setup is clearly explained.
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:
Name | Last_Name | Account | Address | Gift | |
Alvaro | Tejada Galindo | 12345 | 742 Evergreen Terrace | xxx@gmail.com | Deadpool Action Figure |
Blag | Tejada Galindo | 56789 | 430 Spalding Way | xxx@nylas.com | AFI Poster |
Alvaro aka “Blag” | Tejada Galindo | 46451 | 1024 Cherry Street | xxx@gmail.com | Tomb Raider Game |
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.
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:
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:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://cdn.tailwindcss.com"></script> <title>Nylas' Mail Merge</title> </head> <body> <div id="container"> {% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %} <div class="flash bg-green-300 border-green-600 border-b p-4 m-4 rounded w-2/5 grid place-items-center text-red-600 font-bold"> {{ message }} </div> {% endfor %} {% endif %} {% endwith %} {% block content %} {% endblock %} </div> </body> </html>
Then, main.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"> <p class="text-6xl text-center">Mail Merge</p> <br> <form method="post"> <label for="subject" class="font-bold">Subject: </label> <input type="text" name="subject" value="{% if session.subject != None %} {{session.subject}} {% endif %}" size="50"></input> <br><br> <label for="body" class="font-bold">Body: </label> <textarea name="body" rows=5 cols=49>{% if session.body != None %} {{session.body}} {% endif %}</textarea> <br><br> <label for="mergefile" class="font-bold">Merge File: </label> <input type="file" name="mergefile"> <br><br> <button type="submit" class="block bg-blue-500 hover:bg-blue-700 text-white text-lg mx-auto py-2 px-4 rounded-full">Submit</button> </form> </div> {% endblock %}
And finally results.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.
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.
You can sign up for Nylas for free and start building!
Blag aka Alvaro Tejada Galindo is a Senior Developer Advocate at Nylas. He loves learning about programming and sharing knowledge with the community. When he’s not coding, he’s spending time with his wife, daughter and son. He loves Punk Music and reading all sorts of books.