> ## Documentation Index
> Fetch the complete documentation index at: https://docs.allgoodhq.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Liquid recipes for emails

> Copy-ready snippets for tracking links, dates, greetings, and clean text in an email.

These snippets solve problems marketers usually handle with Marketo My Tokens: tracking links, the current year, a safe greeting. Paste one into the email's design, then change the field names to match your template. For the fields you can use, see the [Merge field reference](https://docs.allgoodhq.com/mk/content/email/emails/merge-field-reference.md).

## Tracking links

### Build a campaign name for UTM parameters

Turn a copy field such as `name` into a lowercase, dash-separated value. "Spring Sale: 20% Off!" becomes `spring-sale-20-off`.

```liquid theme={null}
utm_campaign={{ asset.copy.content.name.value | downcase | remove: ":" | remove: "%" | remove: "!" | replace: " ", "-" }}
```

If your campaign names contain only letters and spaces, a shorter version works:

```liquid theme={null}
utm_campaign={{ asset.copy.content.name.value | downcase | replace: " ", "-" }}
```

The short version keeps punctuation. "Spring Sale: 20% Off!" becomes `spring-sale:-20%-off!`, which breaks in many analytics tools. Add one `remove` for each character your names use.

### Tag the link by button

Use the button's label as `utm_content` so reports show which button got the click.

```liquid theme={null}
utm_content={{ asset.copy.content.ctaLabel.value | downcase | replace: " ", "-" }}
```

"See the report" becomes `see-the-report`.

### Add parameters to any link

A link might already have a question mark. Check before you add the first parameter.

```liquid theme={null}
{% assign u = asset.copy.content.ctaUrl.value %}
<a href="{{ u }}{% if u contains '?' %}&{% else %}?{% endif %}utm_source=email">Read more</a>
```

## Dates and times

`send.sentAt` is the moment the email sends. Use it instead of typing a date, so a nurture email stays correct for years.

| You want | Snippet | Result |
| - | - | - |
| Current year | `{{ "now" \| date: "%Y" }}` | 2026 |
| Long date | `{{ send.sentAt \| date: "%B %-d, %Y" }}` | October 26, 2026 |
| Date and time in a time zone | `{{ send.sentAt \| date: "%B %-d, %-I:%M %p", "America/New_York" }}` | October 26, 11:38 AM |
| Month tag for reports | `{{ send.sentAt \| date: "%Y-%m" }}` | 2026-10 |
| Quarter | `Q{{ send.sentAt \| date: "%m" \| minus: 1 \| divided_by: 3 \| plus: 1 }}` | Q4 |
| Seven days from send | `{{ send.sentAt \| date: "%s" \| plus: 604800 \| date: "%B %-d, %Y" }}` | November 2, 2026 |

For other days, change 604800, which is seven days in seconds. One day is 86400.

### Count the days until an event

Subtract the send time from the event time, then round up with `ceil`.

```liquid theme={null}
{% assign ev = asset.copy.content.eventDate.value | date: "%s" | plus: 0 %}
{% assign sent = send.sentAt | date: "%s" | plus: 0 %}
{% assign d = ev | minus: sent | divided_by: 86400.0 | ceil %}
{% if d > 1 %}
  Starts in {{ d }} days.
{% elsif d == 1 %}
  Starts tomorrow.
{% elsif d == 0 %}
  Starts today.
{% else %}
  This event has already happened.
{% endif %}
```

Date math returns decimals unless you finish with `ceil` or `floor`. Without it, you can see "7.6 days". `ceil` rounds up, so 7.6 becomes 8.

### Find the Nth weekday of a month

Say your community meets on the 4th Wednesday of each month, and you want the invite to state the date without anyone typing it. Set the week number and the weekday at the top. The weekday is a number: Sunday is 0, Monday is 1, up to Saturday as 6.

```liquid theme={null}
{% assign nth = 4 %}
{% assign weekday = 3 %}
{% assign ym = send.sentAt | date: "%Y-%m" %}
{% assign first = ym | append: "-01" %}
{% assign w = first | date: "%w" | plus: 0 %}
{% assign offset = weekday | minus: w | plus: 7 | modulo: 7 %}
{% assign dom = nth | minus: 1 | times: 7 | plus: 1 | plus: offset %}
{% if dom < 10 %}{% assign dom = "0" | append: dom %}{% endif %}
{% assign target = ym | append: "-" | append: dom %}
Join us {{ target | date: "%A, %B %-d, %Y" }}.
```

| Send date | After |
| - | - |
| October 26, 2026 | Join us Wednesday, October 28, 2026. |
| May 2, 2024 | Join us Wednesday, May 22, 2024. |
| February 10, 2026 | Join us Wednesday, February 25, 2026. |

The recipe finds the first day of the month, counts how far it is to your weekday, and then adds whole weeks. It works for any week from 1 to 4. Week 5 does not exist in every month, so avoid it.

To invite people to **next** month's meeting, start from next month instead of the send month:

```liquid theme={null}
{% assign y = send.sentAt | date: "%Y" | plus: 0 %}
{% assign m = send.sentAt | date: "%m" | plus: 1 %}
{% if m > 12 %}{% assign m = 1 %}{% assign y = y | plus: 1 %}{% endif %}
{% if m < 10 %}{% assign m = "0" | append: m %}{% endif %}
{% assign ym = y | append: "-" | append: m %}
```

Put these lines in place of the first `ym` line above and keep the rest. A send in December gives a January date in the next year.

### Greet by time of day

Read the hour in the recipient's own time zone.

```liquid theme={null}
{% assign h = send.sentAt | date: "%H", person.timezone | plus: 0 %}
{% if h < 12 %}Good morning{% elsif h < 17 %}Good afternoon{% else %}Good evening{% endif %}
```

If a person has no time zone on file, the hour uses the platform's time zone, so some people see the wrong greeting. Use a neutral greeting for lists with many blank time zones.

## Greetings and fallbacks

### Fall back when a name is blank

Each `default` applies when the field to its left is empty. This chain tries first name, then company, then a plain greeting.

```liquid theme={null}
Hi {{ person.firstName | default: person.companyName | default: "there" }},
```

### Drop a blank name from the subject

A subject like ", your report is ready" looks broken. Print the name and its comma only when a name exists.

```liquid theme={null}
{% if person.firstName %}{{ person.firstName }}, {% endif %}your report is ready
```

### Pull a first name or domain out of another field

```liquid theme={null}
{{ person.fullName | split: " " | first }}
{{ person.email | split: "@" | last }}
```

The first returns the first word of the full name. The second returns the part of the email after the at sign, such as `acme.com`.

## Clean text

| You want | Snippet | Why |
| - | - | - |
| Safe HTML text | `{{ asset.copy.content.headline.value \| escape }}` | "AT\&T Labs" becomes `AT&amp;T Labs` |
| Safe text in a link | `{{ person.companyName \| url_encode }}` | A space becomes `+`, `&` becomes `%26` |
| Address with line breaks | `{{ sender.postalAddress \| newline_to_br }}` | Keeps each line of the address |
| Shorten a long value | `{{ person.title \| truncate: 20, "…" }}` | Stops long titles breaking a layout |
| Change case | `{{ person.lastName \| upcase }}` | Also `downcase` |
| Join a list | `{{ asset.copy.content.points.value \| join: ", " }}` | Turns an array into one line |

> [!WARNING]
>
> Merge fields aren't escaped for you. A company name with an ampersand or a quote can break the HTML around it. Add `escape` to any person field you place inside text or an attribute.

## Singular or plural

```liquid theme={null}
{{ n }} {% if n == 1 %}seat{% else %}seats{% endif %}
```

## More than two outcomes

Add `elsif` branches, or use `case` when you test one field.

```liquid theme={null}
{% case person.lifecycleStage %}
  {% when "Customer" %}Here is your renewal guide.
  {% when "Opportunity" %}Here is a comparison to share with your team.
  {% else %}Here is how to get started.
{% endcase %}
```

## Related articles

* [Merge field reference](https://docs.allgoodhq.com/mk/content/email/emails/merge-field-reference.md)
* [Show content conditionally and repeat a list](https://docs.allgoodhq.com/mk/content/email/emails/conditional-content-and-lists.md)
* [Personalizing an email](https://docs.allgoodhq.com/mk/content/email/emails/personalizing-an-email.md)
* [Previewing and testing an email](https://docs.allgoodhq.com/mk/content/email/emails/previewing-and-testing-an-email.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.