Merge tags
Your users personalise a design by typing merge tags where a person's details go:
Hi {{contact.first_name | "there"}}, your order from {{contact.company}} has shipped.
When you export, you give the values; every tag is replaced, in the subject, the preheader, the HTML and the plain text.
The tags
| Tag | Becomes |
|---|---|
{{contact.<key>}} | The value you pass for <key>. Any key: first_name, company, plan, order_id… |
{{contact.<key> | "fallback"}} | The same, or the fallback when the value is missing or blank |
{{unsubscribe_url}} | Your unsubscribe link |
{{preferences_url}} | Your preferences link (your unsubscribe link when you give none) |
Keys are whatever your product knows about a person. Lettrove has no fixed list: the tags in a design are the ones your users typed.
Filling them at export
const email = await editor.exportHtml({
merge: {
contact: { first_name: 'Ada', company: 'Analytical Engines' },
unsubscribeUrl: 'https://acme.com/unsubscribe/7f3a',
preferencesUrl: 'https://acme.com/preferences/7f3a', // optional
},
});
email.subject; // 'Your order has shipped, Ada'
email.html; // '…Hi Ada, your order from Analytical Engines has shipped…'
email.mergeTags; // [] — nothing left to fill
The same merge works on exportPlainText, the file exports, and on your server:
const email = await lettrove.designs.export(designId, {
user: { id: userId },
merge: { contact: { first_name: 'Ada' }, unsubscribeUrl },
});
Values are written into the HTML safely: a value like <b>Ada</b> appears as that text, never as
markup.
When you pass contact, a tag whose value you did not give takes its fallback, or becomes empty if
it has none. So Hi {{contact.first_name}}, with no first_name reads Hi , — encourage your users
to give tags a fallback ({{contact.first_name | "there"}}).
Leaving them for your email service
Many email services (SendGrid, Mailchimp, Customer.io…) fill their own tags per recipient. Export
without merge and every tag stays exactly as written, for your service to replace:
const { html, mergeTags } = await editor.exportHtml();
mergeTags; // ['{{contact.first_name | "there"}}', '{{unsubscribe_url}}']
mergeTags lists every tag still in the email, exactly as written, so your code can map them to
your service's own syntax before sending.
A link you do not give stays as written too, never blank: export with contact but without
unsubscribeUrl, and {{unsubscribe_url}} is left for your service.
Before you send
Check mergeTags is empty, or that your email service fills every tag in it. A recipient must never
see a raw {{…}}.