- Products
- Solutions Use casesBy industry
- Developers
- Resources Connect
- Pricing
Mail merge consists of using a template to send similar emails to multiple recipients while keeping the content personalized.
And 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. For high-volume sends, using a mail merge template is the way to go.
In this post we will use Gmail as our email service provider to create a mail merge template with Java. With the Nylas Email API, we can easily support utilizing a mail merge template to send communications. Let’s explore how in this blog post.
If you already have the Nylas Java SDK installed and your Java environment is configured, then continue along with the blog.
Otherwise, I would recommend that you read the post How to Send Emails with the Nylas Java SDK where the basic setup is clearly explained.
Before we jump into the code, let’s see how our application actually works. Although for that, we need an essential step, which is creating a .csv file containing all the emails and information that we’re going to use.
The file will look like this, and you can actually choose how you name it:
Name | Last_Name | Account | Address | Gift | |
Alvaro | Tejada Galindo | 12345 | 742 Evergreen Terrace | [email protected] | Deadpool Action Figure |
Blag | Tejada Galindo | 56789 | 430 Spalding Way | [email protected] | AFI Poster |
Alvaro aka “Blag” | Tejada Galindo | 46451 | 1024 Cherry Street | [email protected] | 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 like:
Here, we can fill in the subject, and the body and select the .csv file that we had created.
We will get an error message if we don’t specify all the fields.
The exciting 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. Just keep in mind 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.
Our project is going to be called Mail_Merge, and it will have a main class called MailMerge. We will need to change the default pom.xml file and create two Mustache templates called main and show_emails.
We want to use a web framework, and a very light and fast option is SparkJava.
We’re going to include some useful libraries:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Mail_Merge</groupId> <artifactId>Mail_Merge</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-simple</artifactId> <version>1.7.25</version> </dependency> <dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.9.4</version> </dependency> <dependency> <groupId>com.nylas.sdk</groupId> <artifactId>nylas-java-sdk</artifactId> <version>1.16.0</version> </dependency> <dependency> <groupId>io.github.cdimascio</groupId> <artifactId>dotenv-java</artifactId> <version>2.2.4</version> </dependency> <dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-template-mustache</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>com.opencsv</groupId> <artifactId>opencsv</artifactId> <version>5.5</version> </dependency> </dependencies> </project>
And here’s the source code of our MailMerge.java class:
// Import Java Utilities import java.io.FileReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.lang.Exception; // Import Spark and Mustache libraries import spark.ModelAndView; import static spark.Spark.*; import spark.template.mustache.MustacheTemplateEngine; // Import Opencsv import com.opencsv.CSVReader; //Import Nylas Packages import com.nylas.NylasAccount; import com.nylas.NylasClient; import com.nylas.Draft; import com.nylas.NameEmail; //Import DotEnv to handle .env files import io.github.cdimascio.dotenv.Dotenv; public class MailMerge { public static void main(String[] args) { // Load the .env file Dotenv dotenv = Dotenv.load(); // Create the client object NylasClient client = new NylasClient(); // Connect it to Nylas using the Access Token from the .env file NylasAccount account = client.account(dotenv.get("ACCESS_TOKEN")); // Default path when we load our web application get("/", (request, response) -> { // Create a model to pass information to the mustache template Map<String, Object> model = new HashMap<>(); model.put("subject", ""); model.put("body", ""); // Call the mustache template return new ModelAndView(model, "main.mustache"); }, new MustacheTemplateEngine()); // When we submit the form, we're posting data post("/", (request, response) -> { // Grab the form fields String subject = request.queryParams("subject"); String body = request.queryParams("body"); String merge_file = request.queryParams("merge_file"); // Validate that they are all filled // Otherwise halt execution and display an error message if(subject.equals("") || body.equals("") || merge_file.equals("")){ String halt_msg = "<html>\n" + "<head>\n" + " <script src=\"https://cdn.tailwindcss.com\"></script>\n" + " <title>Nylas' Mail Merge</title>\n" + "</head>\n" + "<body>\n" + "<div class=\"bg-red-300 border-green-600 border-b p-4 m-4 rounded w-2/5 grid place-items-center\">\n" + "<p class=\"font-semibold\">You must specify all fields</p>\n" + "</div>\n" + "</body>\n" + "</html>"; halt(halt_msg); } // Auxiliary variables Integer name = -1; Integer last_name = -1; Integer email = -1; String full_name = ""; String email_address = ""; String [] emails = {}; // Create an Array List of emails ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(emails)); // Read the .csv fil;e CSVReader reader = new CSVReader(new FileReader(merge_file)); // Read the header or the column names String[] col_names = reader.readNext(); String [] nextLine; // Read each line of the .csv file while ((nextLine = reader.readNext()) != null) { // Use extra variables to preserve original values String subject_replaced = subject; String body_replaced = body; // Loop through all the column names for(int i=0;i<col_names.length;i++){ if(col_names[i].equals("Name")){ name = i; } if(col_names[i].equals("Last_Name")){ last_name = i; } if(col_names[i].equals("Email")){ email = i; } // Use a small regex to determine what needs to be // replaced. {Name} with the actual name on the .csv file String pattern_key = "\\{" + col_names[i] + "\\}"; Pattern pattern = Pattern.compile(pattern_key, Pattern.CASE_INSENSITIVE); Matcher matcher = pattern.matcher(subject); boolean matchFound = matcher.find(); if(matchFound) { subject_replaced = subject_replaced.replaceAll(pattern_key, nextLine[i]); } matcher = pattern.matcher(body); matchFound = matcher.find(); if(matchFound) { body_replaced = body_replaced.replaceAll(pattern_key, nextLine[i]); } } // Get name or full name of recipient try{ full_name = nextLine[name] + " " + nextLine[last_name]; }catch(Exception e){ full_name = nextLine[name]; } // Get a list of recipient emails arrayList.add(nextLine[email]); email_address = nextLine[email]; // Create a new draft Draft draft = new Draft(); // Set the subject of the message draft.setSubject(subject_replaced); // Set the body of the message draft.setBody(body_replaced); // Specify the recipient of the email draft.setTo(Arrays.asList(new NameEmail(full_name, email_address))); try { //Send the email draft account.drafts().send(draft); }catch (Exception e){ } } // Convert the ArrayList back to an Array emails = arrayList.toArray(emails); // Pass the emails as a parameter to the mustache template Map<String, Object> model = new HashMap<>(); model.put("emails", emails); return new ModelAndView(model, "show_emails.mustache"); }, new MustacheTemplateEngine()); } }
Inside the resources folder, we need to create a templates folder and inside we need to create 2 different files, let’s start with main.mustache:
<html> <head> <script src="https://cdn.tailwindcss.com"></script> <title>Nylas' Mail Merge</title> </head> <body> <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="{{subject}}" size="50"></input> <br><br> <label for="body" class="font-bold">Body: </label> <textarea name="body" rows=5 cols=49>{{body}}</textarea> <br><br> <label for="merge_file" class="font-bold">Merge File: </label> <input type="file" name="merge_file"> <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> </body> </html>
Then, show_emails.mustache:
<html> <head> <script src="https://cdn.tailwindcss.com"></script> <title>Nylas' Mail Merge</title> </head> <body> <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> {{#emails}} <p class="font-semibold">{{.}}</p> {{/emails}} </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> </body> </html>
And that’s it. We’re ready to roll.
In order to run our application, we need to compile it by typing the following on the terminal window:
$ mvn package
To actually run the application, we need to type the following:
$ mvn exec:java -Dexec.mainClass="MailMerge"
Our application will be running on port 4567 of localhost, so we just need to open our favourite browser and go to the following address:
http://localhost:4567
We easily created a mail merge template application using Java.
If you want to learn more about the Nylas Email API, please visit our documentation Email API Overview.
Sign up for your Nylas account and start building for free.
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.