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
datefilter ({{ Order.ScheduledAt | date }}); a start–end pair becomes a single localized string withdate_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.