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.
Is your system ready?
If you already have the Nylas Java SDK installed and your Java environment is configured, then continue along with the blog.
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:
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.
Creating the project
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.
Creating the pom.xml file
We’re going to include some useful libraries:
spark-core → The Spark Web Framework
nylas-java-sdk → The Nylas Java SDK
dotenv-java → To enable using .env files
spark-template-mustache → To allow mustache on Spark projects
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: