Mail Merge

Learn how to send customized emails to multiple recipients with Mail Merge function.

Using this technique you can define an email template which contains special fields such as {firstname}, {lastname} or many others and send personalized emails in a very efficient way to your clients.
For example:

Dear {firstname} {lastname},

This is our monthly newsletter. We hope you have been enjoying our service. You can access your account at {link}.

If you would like to allow custom headers, please make sure this has been activated on your advanced options screen.

Create a CSV file

Create a CSV file like the following:


"", "Jackie","Smith"

The first column of the data must be ToEmail and will be used as the recipients of the merged email. The other columns represent the data fields that you can use in your email. You can have as many columns as you need. If you have the header FirstName you can include that in your email template with {FirstName} and all references to that field will be replaced before sending.

Send Email

To use the send POST command to with the following form values:

username=your account email address,

api_key=your API key,

from=from email address,

from_name=display name for from email address,

subject=email subject,

body_html=html email body [optional],

body_text=text email body [optional],

mergesourcefilename=your CSV file name sent with this call as an attachment,

charset=text value of encoding for example: iso-8859-1, windows-1251, utf-8, us-ascii, windows-1250 and more…,

encoding for None, 1 for Raw7Bit, 2 for Raw8Bit, 3 for QuotedPrintable, 4 for Base64 (Default), 5 for Uue (note that you can also provide the text version such as "Raw7Bit" for value 1).

If sent correctly you will receive a response like:


This contains the transaction ID of your send job. You can use this transaction ID to check on the statistics of the given job using the Get Status API.

Your email will be sent to each email address in the CSV file and the data will be merged with the CSV data.

Note: There is a limit of 100000 emails / uploaded CSV file for larger jobs please split into separate calls.

Mail Merge with single recipient

You can also use the merge fields when sending to a single recipient. You can, of course, create a CSV file with one recipient and follow our instructions mentioned above, or you could create the merge fields' values on the go:
Simply use a merge field in your bodyHtml or bodyText ("Hello, {firstname}" etc.) and provide it's value in the same request by following the given convention:

merge_X = Y

For the given firstname, it would be:


Implement how many fields you need and provide them with the Send request just as you would provide a subject, or bodyHtml, and you are ready to go!


using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;

namespace ElasticEmailClient
    class Program
        static void Main(string[] args)
            NameValueCollection values = new NameValueCollection();
            values.Add("apikey", "00000000-0000-0000-0000-000000000000");
            values.Add("from", "");
            values.Add("fromName", "Your Company Name");
            values.Add("subject", "Your Subject");
            values.Add("bodyText", "Hello, {firstname}");
            values.Add("bodyHtml", "<h1>Hello, {firstname}</h1>");
			values.Add("mergesourcefilename", "mycontacts.csv"); // Same as the name of the file in the 'filenames' array
            string address = "";

            var filepath = "C:\\example\\contacts.csv";
            var file = File.OpenRead(filepath);

			// multiple files can be sent using this method
            var filesStream = new Stream[] { file };
            var filenames = new string[] { "mycontacts.csv" };
            var URL = "";

            string result = Upload(URL, values, filesStream, filenames);


        public static string Upload(string actionUrl, NameValueCollection values, Stream[] paramFileStream = null, string[] filenames = null)
            using (var client = new HttpClient())
            using (var formData = new MultipartFormDataContent())
                foreach (string key in values)
                    HttpContent stringContent = new StringContent(values[key]);
                    formData.Add(stringContent, key);

                for (int i = 0; i < paramFileStream.Length; i++)
                    HttpContent fileStreamContent = new StreamContent(paramFileStream[i]);
                    formData.Add(fileStreamContent, "file" + i, filenames[i]);

                var response = client.PostAsync(actionUrl, formData).Result;
                if (!response.IsSuccessStatusCode)
                    throw new Exception(response.Content.ReadAsStringAsync().Result);

                return response.Content.ReadAsStringAsync().Result;



$url = '';
$filename = "contacts.csv";
$file_name_with_full_path = realpath('./'.$filename);

	$post = array('from' => '',
		'fromName' => 'Your Company Name',
		'apikey' => '00000000-0000-0000-0000-000000000000',
		'subject' => 'Your Subject',
		'bodyHtml' => '<h1>Hello, {firstname}</h1>',
		'bodyText' => 'Hello, {firstname}',
		'isTransactional' => false,
		'file_contacts' => new CurlFile($file_name_with_full_path, 'text/csv', $filename),
		'mergesourcefilename' => $filename);
		$ch = curl_init();
		curl_setopt_array($ch, array(
			CURLOPT_URL => $url,
			CURLOPT_POST => true,
			CURLOPT_HEADER => false,
		$result=curl_exec ($ch);
		curl_close ($ch);
		echo $result;	
catch(Exception $ex){
	echo $ex->getMessage();


import java.util.HashMap;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ElasticClient {
    public static void main(String[] args) {
        API client = new API();
        ArrayListfiles = new ArrayList<>();
        String filename = "Contacts.csv";
        Path path = Paths.get("C:\\example\\" + filename);
        byte[] data = null;
        try {
            data = Files.readAllBytes(path);
        } catch (IOException ex) {
            Logger.getLogger(ElasticClient.class.getName()).log(Level.SEVERE, null, ex);
        FileData contactsFile = new FileData();
        contactsFile.contentType = "text/csv";
        contactsFile.fileName = filename;
        contactsFile.content = data;
        HashMap<String, String> values = new HashMap<>();
        values.put("apikey", "00000000-0000-0000-0000-000000000000");
        values.put("from", "");
        values.put("fromName", "Your Company Name");
        values.put("subject", "Your Subject");
        values.put("bodyText", "Hello, {firstname}");
        values.put("bodyHtml", "<h1>Hello, {firstname}</h1>");
        values.put("mergesourcefilename", filename);
        try {
            String result = client.httpPostFile("/email/send", files, values);
        } catch (Exception ex) {
            Logger.getLogger(ElasticClient.class.getName()).log(Level.SEVERE, null, ex);

-------------- ----------------

import java.nio.charset.Charset;
import java.util.Map;

public class API {
    public static String API_KEY = "";
    protected static String API_URI = "";

    protected String httpPostFile(String targetURL, Iterable fileData, Map<String, String> values) throws Exception {
        if (targetURL == null) throw new IllegalArgumentException("targetURL");
        if (values == null) throw new IllegalArgumentException("values");
        if (fileData == null) throw new IllegalArgumentException("fileData");

        HttpURLConnection connection = null;
        URL url = null;
        String urlParameters = null;
        String urlParametersLength = null;

        try {
            url = new URL(API_URI + targetURL);
            urlParameters = loadUrlParameters(values);
            urlParametersLength = Integer.toString(urlParameters.getBytes().length);
            String boundary = String.valueOf(System.currentTimeMillis());
            byte[] boundarybytes = ("\r\n--" + boundary + "\r\n").getBytes(Charset.forName("ASCII"));

            connection = (HttpURLConnection)url.openConnection();
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Content-Length", "" + urlParametersLength);

            //Send request
            DataOutputStream wr = new DataOutputStream(connection.getOutputStream ());

        String formdataTemplate = "Content-Disposition: form-data; name=\"%s\"\r\n\r\n%s";
        for (String key : values.keySet())
            wr.write(boundarybytes, 0, boundarybytes.length);
            String formitem = String.format(formdataTemplate, key, values.get(key));
            byte[] formitembytes = formitem.getBytes(Charset.forName("UTF8"));
            wr.write(formitembytes, 0, formitembytes.length);

        if(fileData != null){
            for(FileData file : fileData){
                wr.write(boundarybytes, 0, boundarybytes.length);
                String headerTemplate = "Content-Disposition: form-data; name=\"filefoobarname\"; filename=\"%s\"\r\nContent-Type: %s\r\n\r\n";
                String header = String.format(headerTemplate, file.fileName, file.contentType);
                byte[] headerbytes = header.getBytes(Charset.forName("UTF8"));
                wr.write(headerbytes, 0, headerbytes.length);
                wr.write(file.content, 0, file.content.length);

        byte[] trailer = ("\r\n--" + boundary + "--\r\n").getBytes(Charset.forName("ASCII"));
        wr.write(trailer, 0, trailer.length);
        wr.flush ();
        wr.close ();

        //Get Response	
        InputStream is = connection.getInputStream();
        BufferedReader rd = new BufferedReader(new InputStreamReader(is));
        String line;
        StringBuilder response = new StringBuilder(); 
        while((line = rd.readLine()) != null) {

        return response.toString();

        } catch (IOException e) { 
            return null;

        } finally {
            if(connection != null) {
    private String loadUrlParameters(Map<String, String> values) {
        StringBuilder sb = new StringBuilder();

        values.keySet().forEach((key) -> {
            if (sb.length() > 0) {
            String value = values.get(key);
            try {
                sb.append((key != null ? URLEncoder.encode(key, "UTF-8") : ""));
                sb.append(value != null ? URLEncoder.encode(value, "UTF-8") : "");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException("This method is not supported", e);
        return sb.toString();

---------------- -----------------------

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileData {
    public byte[] content;
    public String contentType;

    public String fileName;
    public void ReadFrom(String pathWithFileName) throws Exception
    	Path path = Paths.get(pathWithFileName);
        content = Files.readAllBytes(path);
        fileName = path.getFileName().toString(); 
        contentType = null;

    public static FileData CreateFromFile(String pathWithFileName) throws Exception
        FileData fileData = new FileData();
        return fileData;


import requests
import json
from enum import Enum

class ApiClient:
	apiUri = ''
	apiKey = '00000000-0000-0000-0000-000000000000'

	def Request(method, url, data, attachs=None):
		data['apikey'] = ApiClient.apiKey
		if method == 'POST':
			result = + url, params = data, files = attachs)
		elif method == 'PUT':
			result = requests.put(ApiClient.apiUri + url, params = data)
		elif method == 'GET':
			attach = ''
			for key in data:
				attach = attach + key + '=' + data[key] + '&' 
			url = url + '?' + attach[:-1]
			result = requests.get(ApiClient.apiUri + url)	
		jsonMy = result.json()
		if jsonMy['success'] is False:
			return jsonMy['error']
		return jsonMy['data']

def Send(subject, EEfrom, fromName, bodyHtml, bodyText, isTransactional, contactsSourceFilename, attachmentFiles = []):
	attachments = []
	for name in attachmentFiles:
		attachments.append(('attachments'.name, open(name, 'rb')))
	return ApiClient.Request('POST', '/email/send', {
		'subject': subject,
		'from': EEfrom,
		'fromName': fromName,
		'bodyHtml': bodyHtml,
		'bodyText': bodyText,
		'mergesourcefilename': contactsSourceFilename,
		'isTransactional': isTransactional}, attachments)
attachments = []
print(Send("Your Subject", "", "Your Company Name", "<h1>Hello, {firstname}</h1>", "Hello, {firstname}", True, "Contacts.csv", attachments))


All code samples are licensed under MIT license.