Skip to main content
Shortcodes personalize your emails. Write {{ contact.firstName }} once, and every recipient sees their own name.
Renders as: Hi Ada, thanks for shopping with Acme Supply Co! This page is the full syntax reference. To insert a tag from the editor toolbar instead of writing it by hand, see Personalization.

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.
Renders as 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 opens Hi ,.
  • 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

Abandoned-cart automations only. In any other email these render blank.
  • Keep the .size > 0 check. 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

Automations with a coupon step only. These never work in broadcasts.
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:
To show an expiry, add the 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 > 0 guard. 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.
Automation templates only. The Summary block is not available in broadcast campaigns.
Stripped of its layout tables and Outlook-only comments, a default Summary block is:
This produces one entry per item: an image, then Classic White T-Shirt × 2, then $59.98.
{{ item.price }} is already the line total — never multiply it. {{ item.price | times: item.quantity }} counts the quantity twice: a 2 × $29.99 line shows $119.96 instead of $59.98. For “unit × qty = total”, write {{ item.unitPrice }} × {{ item.quantity }} = {{ item.price }}.
  • 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, not item — write {{ line.name }} there.
  • If you edit the source: keep the htmlmin:ignore HTML comments shown above (they stop the loop tags being mangled), do not rename item, and do not change event.line_items. limit:9999 means no limit — lower it to cap how many items show.
  • In preview it shows placeholder textProduct Title, Quantity, $xx.xx, and a grey image. Real values appear on send.

Unsubscribe

Works in every email.
Unique per contact, and legally required in marketing email. If your email has no unsubscribe link, Retainful adds one automatically — but placing it yourself looks better. See Deliverability best practices.

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:
Incorrect — the block always shows:
The plain form looks right but does not work. An empty value is still “something” as far as Liquid is concerned, so the block renders anyway, with a blank inside it. That is what produces an anchor tag with an empty 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" }}.