Skip to main content

Variables & data

Every template is bound to a typed data model through its context key. The model defines which fields are available for substitution at send time.

The model

Each context key (Order, Event, User, …) corresponds to a fixed shape maintained by backend code:

  • Top-level fields (Order.OrderNumber, Order.CustomerName)
  • Nested objects (Order.DeliveryAddress.City)
  • Collections (Order.LineItems)
  • Typed values (strings, numbers, dates, booleans)

When a render is requested, the caller supplies an instance of that model.

Referencing fields in MJML

Template authors reference fields directly inside their MJML. The system replaces every reference with the corresponding value from the supplied data.

Missing fields are flagged at validation time — typos are caught when the template is saved, not at 3 a.m. on send day.

Formatting

Values are transformed at the point of use with filters:

  • Dates render automatically in each recipient's timezone, language, and clock preference via the date filter ({{ Order.ScheduledAt | date }}); a start–end pair becomes a single localized string with date_range. Authors don't pass format strings or timezones — output is consistent for everyone.
  • Defaults can be supplied inline so an empty field doesn't leave a blank spot in the email ({{ Order.Note | default: '—' }}).
  • Lists can be joined into human-readable strings with a chosen separator.

The formatting layer is consistent across all templates — see Filters for the full set.

Why typed models matter

  • Compile-time safety on the backend. When the model class is updated, the compiler points at every code path that needs adjustment.
  • Validation on the template. Saving a template that references a non-existent field fails fast.
  • Clear contracts. Each template documents itself: read the context key, look up the model, you know exactly what data it can use.

What this means for authors

You can confidently reach for any field on the model. You don't need to worry about whether the value is null, missing, or wrong-typed — the system either substitutes a sensible representation or rejects the change before it ships.