Mail merge with EmailEngine

While EmailEngine makes it easy to send regular email through the user's SMTP server with REST API calls, it is also possible to use mail merge. To use it, you need to drop all the regular To/Cc/Bcc addresses from the API request and replace them with an array called mailMerge. This array takes a list of targets (and target-specific template values if you want to send personalized emails).

The main difference between specifying multiple To addresses, and using the mail merge is that each recipient will get a distinct copy of the message with mail merge so that these recipients would only see their own address in the To header.

NB! EmailEngine uploads each sent message to the account's "Sent Mail" folder. If you don't need this behavior, set "copy": false for the message structure.

You can use any other EmailEngine's email sending feature with mail merge emails as well. For example, delayed sending or clicks/opens tracking.

Example 1. Sending the same message to multiple recipients as mail merge.

Everything else would look the same as sending a single email, but instead of regular recipients array, we provide the mailMerge value.

$ curl -XPOST "https://ee.example.com/v1/account/example/submit" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer 383a109846...0df1cc" \
  -d '{
    "subject": "Test message",
    "html": "<p>Each recipient will get the same message</p>",
    "mailMerge": [
      {
        "to": {
          "name": "Andris Reinman",
          "address": "andris.reinman@gmail.com"
        }
      },
      {
        "to": {
          "name": "Andris Ethereal",
          "address": "andris@ethereal.email"
        }
      }
    ]
  }'
The API call is missing the from address. EmailEngine uses account data to fill in the sender details itself.

The other difference with single emails is that as EmailEngine generates a separate copy for each recipient, each of these copies will get a distinct Message-ID header value. These values are included in the API response, so you can later track which message was sent to which recipient.

{
  "mailMerge": [
    {
      "success": true,
      "to": {
        "name": "Andris Reinman",
        "address": "andris.reinman@gmail.com"
      },
      "messageId": "<91853631-2329-7f13-a4df-da377d873787@example.com>",
      "queueId": "182080c50b63e7e232a"
    },
    {
      "success": true,
      "to": {
        "name": "Andris Ethereal",
        "address": "andris@ethereal.email"
      },
      "messageId": "<8b47f91c-06f3-b555-ee19-2c99908aff25@example.com>",
      "queueId": "182080c50f283f49252"
    }
  ],
  "sendAt": "2022-07-16T17:26:41.078Z"
}
As each merge message also has a distinct outbox queue ID, you can cancel individual emails if needed.

Each recipient will see the same message but only themselves as the recipient.

Only a single address on the To field, even though we sent the same message to multiple recipients.

Example 2. Sending personalized messages to multiple recipients as mail merge.

This time we will be sending personalized messages. That is, each recipient will get a unique version of the same email.

To achieve this, we can use handlebars syntax for the subject/html/text fields and set the personalized values for each recipient in the mailMerge array.

EmailEngine uses the same handlebars syntax as SendGrid. You can read the details from here.
NB! For plaintext fields like subject and text, use triple-braces notation. For example, {{{params.name}}} instead of {{params.name}}. This is because Handlebars, by default, with double braces, escapes HTML special characters. With triple-braces, all characters are kept as is.

The keys in the mailMerge list can be referenced as {{params.KEY_NAME}}. You can also use {{account.email}}, {{account.name}} and {{service.url}} as special values.

curl -XPOST "https://ee.example.com/v1/account/example/submit" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer 383a109846...0df1cc" \
  -d '{
    "subject": "Test message for {{{params.nickname}}}",
    "html": "<p>This message is for {{params.nickname}}</p>",
    "mailMerge": [
      {
        "to": {
          "name": "Andris Reinman",
          "address": "andris.reinman@gmail.com"
        },
        "params": {
          "nickname": "andris"
        }
      },
      {
        "to": {
          "name": "Andris Ethereal",
          "address": "andris@ethereal.email"
        },
        "params": {
          "nickname": "ethereal"
        }
      }
    ]
  }'

And the result is a personalized email for each recipient.

Example 3. Sending mail merge with prepared templates.

The third example uses mail merge with prepared templates. Prepared templates are content templates stored in the server. When sending an email, you provide the template ID instead of subject/html/text fields, as EmailEngine will populate these fields based on the stored template itself.

You can see the Template API endpoints from the documentation, but in this case, I'll be using the web UI to create a template.

Once you save the template contents, you'll see the required ID value for our API call.

Now that we have the template stored in the server, we can use it for mail merge.

curl -XPOST "https://ee.example.com/v1/account/example/submit" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer 383a109846...0df1cc" \
  -d '{
    "template": "AAABgggrm00AAAABZWtpcmk",
    "mailMerge": [
      {
        "to": {
          "name": "Andris Reinman",
          "address": "andris.reinman@gmail.com"
        },
        "params": {
          "nickname": "andris"
        }
      },
      {
        "to": {
          "name": "Andris Ethereal",
          "address": "andris@ethereal.email"
        },
        "params": {
          "nickname": "ethereal"
        }
      }
    ]
  }'
Note that this time there is no subject or html field. Instead, there's template.

As you can already guess what the resulting message should look like, here's the result:

That's it. Happy sending!