{{ contact.firstName }} once, and every recipient sees their own name.
Where each group works
Not every shortcode works in every email. Using one outside its context leaves it blank rather than raising an error.Customer details
Works in every email — broadcasts and automations.Hi Ada, — or Hi there, for a contact with no first name.
- Always add
| default:. Most contacts have only an email address, so without a fallback your email opensHi ,. - Always write
contact.in front.{{ firstName }}on its own silently fails in broadcast emails. {{ contact.fullName }}shows the email address when both names are blank. For greetings,{{ contact.firstName | default: 'there' }}is safer.
Store
Works in every email.- In broadcasts these work in the email body but not in the subject line. In automations they work in both.
{{ retainful_shop_url_with_coupon_code }}requires a coupon step in the workflow. In a broadcast it drops the coupon silently and links to your store.
Abandoned cart
- Keep the
.size > 0check. Without it, an email with no cart still shows the button, linking nowhere. See Hide empty values correctly. - The coupon version also requires a coupon step in the workflow.
Coupon
The dynamic coupon is added with the Coupon block — drag it in and Retainful writes the code and its checkout link for you. Each contact receives a unique code.
The Coupon block renders the code as a link that sends the shopper straight to checkout with the coupon already applied:
date filter:
- Insert the coupon with the Coupon block, not by hand. The block writes the link and token for you, and it’s where you choose which coupon the flow uses.
- When there’s no coupon,
{{ retainful_dynamic_coupon }}renders empty — the code token needs no.size > 0guard. Any label you add around it (Your code:) still shows on its own, so keep that text inside the block. - Always keep the
| date:filter on{{ retainful_coupon_expiry_date }}— without it you get a raw timestamp. The product default format is%d-%m-%y %H:%M. - The expiry clock starts when the coupon is created, so every email in a sequence shows the same date.
Summary block
Lists the items your customer ordered or left in their cart. Drag the block in and the editor writes the loop for you — you only edit what is inside it.
Stripped of its layout tables and Outlook-only comments, a default Summary block is:
Classic White T-Shirt × 2, then $59.98.
- Show or hide the name and price, and set their colour and size, in the block’s settings panel. You do not need to touch the shortcodes.
- The Review block is the same thing with a button, but its loop variable is
line, notitem— write{{ line.name }}there. - If you edit the source: keep the
htmlmin:ignoreHTML comments shown above (they stop the loop tags being mangled), do not renameitem, and do not changeevent.line_items.limit:9999means no limit — lower it to cap how many items show. - In preview it shows placeholder text —
Product Title,Quantity,$xx.xx, and a grey image. Real values appear on send.
Unsubscribe
Works in every email.Four rules worth knowing
Always add a fallback
default covers every “no value” case — blank, never set, or missing.
Hide empty values correctly
To hide a block when a shortcode has no value, test.size > 0:
Correct:
href — a real button that goes nowhere.
.size > 0 is safe on every shortcode in this document.
Typos are invisible
{{ contact.frstName }} renders as empty space. No error, no warning. Proofread, and always send a test email.
A test proves your spelling is right, not that the data will be there. A test send fills in sample values even for shortcodes that come back blank on a real send.
Do not invent tags
Only use what is in this document. A made-up{% tag %} — such as {% current_year %} — breaks the whole email: every shortcode disappears and the raw tag is shown to your customer.
For the current year, use {{ "now" | date: "%Y" }}.