**Email personalization** allows you to tailor email content to each recipient by using attributes and placeholders. This helps you create more relevant and engaging messages while reaching many customers at once.

---

## Placeholders

Use **placeholders** to personalize your emails with standard and custom attributes, such as names, account numbers, or other profile data. This makes each message feel tailored to the recipient, even when sending to a large audience.
Standard and custom attributes are linked to People profiles. See [People](https://www.infobip.com/docs/people/manage-data) to learn more about attributes and how to set them up.

When adding a link, you can also define it as a **special link**:

- **View in browser**: `{$browserlink}`
- **Unsubscribe**: `{$unsubscribe}`

Note
The **View in browser** link **expires after 5 days**. This feature is **not** enabled by default for email traffic sent via API. To enable it, contact [Support](mailto:support@infobip.com) or your account manager.

---

## Simple expressions

**Simple expressions** let you format and manipulate any personalization you add to an email message. The available options depend on the data type of the attribute you insert, ensuring consistent display.

Supported formatting options:

- **String**: Proper case, lower case, upper case
- **Numeric**: Round (down if less than X.5, up if greater than or equal to X.5), floor (always round down), format with two decimals
- **Date/Time**: US format (yyyy-MM-dd or yyyy-MM-dd hh:mm), EU format (dd/MM/yyyy or dd/MM/yyyy hh:mm), day of year, day of week, month of date

**Example:**

If you insert the `firstName` attribute, you can format it as:

- Proper case → _John_
- Lower case → _john_
- Upper case → _JOHN_

---

## Display conditions

Display conditions let you define rules for showing or hiding content in your email. This ensures each recipient sees content tailored to their attributes or interests, even when the same message is sent to the entire audience. You can create up to 50 conditions per message.

### How to create a display condition [#how-to-create-a-display-condition-display-condition]

To create a display condition:

1. In the **Email Editor**, go to the **Display conditions** tab.
2. Select **Create condition**.
3. Enter a **Name** and **Description**.
4. Select an **Attribute** (for example, Interest = Messaging).
5. To create more complex logic, use **AND** or **OR** operators (for example, Interest = Messaging OR Technology).
6. Select **Save**.

### Assigning a condition to content [#assigning-a-condition-to-content-display-condition]

To assign a display condition to your content:

1. In your email design, select the row or content block.
2. In the property panel, select **Add display condition**.
3. Choose the condition you want to apply.
4. Test your conditions in **Preview** by using the **Test placeholders** tab.

**Example**:

If your newsletter contains multiple topics, you can use display conditions to show only the sections that match the recipient’s interests (for example, messaging or technology).

---

## Repeat block

The **repeat block** feature lets you add personalized lists to your email messages, where items are dynamically loaded for each campaign or recipient. Use repeat blocks to create messages such as:

- Cart abandonment reminders
- Newsletters
- Low stock alerts
- Price drop notifications
- Policy expiration reminders

A repeat block works by looping over a list (array) of data and automatically repeating a section of your template for each entry in that list. Item properties are dynamically inserted into each repeated block.

### How to create a repeat block [#how-to-create-a-repeat-block-repeat-block]

To create a repeat block:

1. Create a **Custom email** message or open a template.
2. Design the layout for the content you want to display.
3. Select the block you want to repeat.
4. Select the **Placeholder** icon.
5. In the pop-up window, choose the list of items (from [Catalogs](https://www.infobip.com/docs/catalogs) or [List attributes](https://www.infobip.com/docs/people/manage-data#lists)).
6. To refine your list, select **Filter** to define which items should appear.
7. Set the **Maximum amount** of items to display.

> **Best practice**:
> Limit repeat blocks to 15 items per message for optimal performance and readability.

### Personalization with Catalogs [#personalization-with-catalogs-repeat-block]

If **[Catalogs](https://www.infobip.com/docs/catalogs)** are your source of data, you can match items to each recipient to personalize your message:

1. Choose the **Catalog field** you want to match to a **[People attribute](https://www.infobip.com/docs/people/manage-data#attributes)**. Only items that match the recipient’s attribute are shown in the email.
2. Add multiple match rules to tailor the list further. For example, show products from the Catalog that match the recipient’s **Size** and also fall under a **Category** they are interested in.
3. Use the **Sort** option to control the order in which items are displayed.
4. Under the **Available placeholders** section, review the data you can dynamically insert into your message.
5. Select **Preview** to test how the personalized list appears for each recipient.

## Template language

The new **template language** introduces a more powerful, readable, and standardized syntax for dynamic email content. Use the template language within your HTML content and define placeholder values in the `to` parameter of your request.

**Recommended syntax for new projects**:

- **Placeholders**: `{$placeholder}`
- **Expressions**: `{{ ... }}`
- **Logic tags**: `{% ... %}`

### Tags [#tags-template-language]

Tags create logic and control the flow of templates. They are denoted with curly braces and percent signs:

- `{% tag %}`

### Conditions [#conditions-template-language]

Use the `{% if %}` tag to show content based on whether an expression evaluates to true.

Close every block with `{% endif %}`. You can extend logic with `{% elseif %}` and `{% else %}`.

**Example**:

| **Input**                                                                                   | **Output** |
|---------------------------------------------------------------------------------------------|------------|
| `{% if {$firstName} == "Alex" %} Hey Alex!{% elseif {$firstName} == "Anna" %}Hey Anna!{% else %}Hi Stranger!{% endif %}` | Hey Anna!  |

### Operators [#operators-template-language]

You can use logical and comparison operators inside `if` statements.

Operator examples

|  |  | 
| != | does not equal | {% if {$firstName}  != "Alex" %}Hey, you!{% endif %} |
| > | greater than | {% if {$score}  > 50 %}Congratulations!{% endif %} |
| < | less than | {% if {$score}  < 50 %}I'm sorry, but you lost{% endif %} |
| >= | greater than or equal to | {% if {$grade}  >= 95 %}Congratulation, you passed!{% endif %} |
| <= | less than or equal to | {% if {$grade}  <= 30 %}You failed{% endif %} |
| or | logical or | {% if {$season} == “Summer” or {$weather} == “Hot” %}It’s time for ice cream!{% endif %} |
| and | logical and | {% if {$gender}  == “Female” and  {$married} == “yes” %}Hello, Mrs.  {$lastName}!{% endif %} |
| not | logical notNegates a boolean expression | {% if not {$hasAccount} %}Please, register!{%else%}Hello, customer!{% endif %} |
| contains | Checks for the presence of a substring inside a stringCan also check for the presence of a string in an array of strings. | {% if {$productTile} contains “Jeans” %}This product’s title contains the word Jeans.{% endif %}{% if {$products}[0] contains 'title' %}You have {{ {$product}[0].title }} in your cart.{%endif%} |
| even | Checks if number is even | {% if {$number} is even %}4 is even!{% endif %} |
| odd | Checks if number is odd | {% if {$number} is odd %}5 is odd!{% endif %} |

### Loops [#loops-template-language]

Use `{% for %}` to iterate through collections such as arrays or objects. Add `limit:n` to restrict the number of iterations. Close every block with `{% endfor %}`.

#### Iterating over a list of elements

| Input | Output |
| --- | --- |
| You left products in your cart:`{% for item in {$cart} limit:3 %}``{{ product }}`{% endfor %}` | You left products in your cart: ShirtJeansShoes |

#### Iterating over a list of objects

| Input | Output |
| --- | --- |
| You left products in your cart:`{% for item in {$cart}  limit:3 %}``{{ item['name'] }}, {{ item['price'] }}, {{ item['quantity'] }}`{% endfor %}` | You left products in your cart: Shirt, 10 EUR, 2 Jeans, 20 EUR, 1 Shoes, 50 EUR, 1 |

### Calculate the item position in the list [#calculate-the-item-position-in-the-list-template-language]

You can calculate the size of your list and add rules depending on the position of the item in the list.

| Input | Output |
| --- | --- |
| Your Policies for`{% for item in {$Policies} limit:3 %}``{{ item['Name'] }}``{% if not loop.last %}` and`{% endif %}`{% endfor %}` expire in 10 days. Renew now on our app and get cash rebates for driving less. | Your Policies forABC1 and ABC2 expire in 10 days. Renew now on our app and get cash rebates for driving less. |

### Expressions [#expressions-template-language]

You can include expressions inside your email templates using the expression function. For details, see [Expression Language](https://www.infobip.com/docs/expression-language).

Expression examples

|  |  | 
| lower | Converts a string into all lowercase. | Input: { expression('lower({$title})') }Output: hello, dear friend! |
| upper | Converts a string into all uppercase. | Input: { expression('upper({$title})') }Output: HELLO, DEAR FRIEND! |
| proper | Converts a string into proper case by making words start with an uppercase character and the remaining characters lowercase. | Input: { expression('proper({$title})') }Output: Hello, Dear, Friend! |
| **Number formatting** |
| numberformat | Formats a decimal number. Use the "#" symbol to control how many symbols after the dot you want to show. | Input: Price is: {{ {$price} | numberformat('#.##') }} EUROutput: Price is: 5.00 EUR |
| round | Returns the value of a number rounded to provided amount of digits after the decimal point. | Input: {{ expression('round({$pi}, 2)') }}Output: 3,14 |
| floor | Returns the value of a number rounded down to the nearest integer value. | Input: {{ expression('floor({$pi}') }}Output: 3 |
| **Date formatting**For more information see [Pebble date filter documentation](https://pebbletemplates.io/wiki/filter/date/). |
| date | Formats the date using the provided pattern.An alternative way to use this filter is to use it on a string but then provide two arguments: the first is the desired pattern for the output, and the second is theexisting formatused to parse the input string. | Input: {{ expression('formatDate({$birthDate}, "dd.MM.yyyy")') }}Output:  01.05.2000Input: {{ "May 01, 2000" | date("yyyy-MM-dd", existingFormat="MMMM dd, yyyy") }}Output: 2000-05-01 |
| dayOfYear | Returns the day of the year for a given date as a number from 1 to 366. | Input: {{ expression('dayOfYear({$birthDate})') }}Output: 121 |
| dayOfMonth | Returns the day of the month for a given date as a number from 1 to 31. | Input: {{ expression('dayOfMonth({$birthDate})') }}Output: 1 |
| dayOfWeek | Returns the day of the week for a given date as a number between 1 (Sunday) and 7 (Saturday). | Input: {{ expression('dayOfWeek({$birthDate})') }}Output: 2 |
| **Math functions** |
| +, -, *, / | All the regular math operators are available for use. Order of operations applies. | Input: Price without tax: {$price} EUR. With tax: {{ {$price} + ({$price} * {$taxSize}) }} EUR.Split for 4 payments (without tax): {{ {$price}/4 }} EUR.Output: Price without tax: 8 EUR. With tax: 9.04 EUR.Split for 4 payments (without tax): 2 EUR. |

---