If you’ve ever built transactional emails in Mautic and wished you could show or hide content based on the data you’re sending, you know the frustration. Mautic’s default token system is great for simple replacements like {firstname}, but what if you need to display a discount row only when a discount exists? Or loop through a list of order items?
That’s exactly why I built the Mautic Twig Enhancements plugin.
The problem
Mautic’s built-in token system handles basic variable replacement well. You pass {order_id} in your API call, and it appears in the email. Simple.
But real-world transactional emails aren’t that simple. Consider a receipt email:
- Show the discount row only if a discount was applied
- Display credit used only if the customer used store credit
- Include a custom message only when one is provided
- Loop through multiple line items in an order
With vanilla Mautic, you’d either show empty rows (ugly) or create multiple email templates for different scenarios (unmaintainable).
The solution
The Mautic Twig Enhancements plugin brings full Twig templating power to your Mautic emails. Twig is the same templating engine used by Symfony (which Mautic is built on), so it’s battle-tested and well-documented.
With this plugin, you can write:
{% if discount is defined and discount %}
<tr>
<td>Discount</td>
<td>{{ discount }}</td>
</tr>
{% endif %}
If discount isn’t in your API payload, that entire row disappears from the email. Clean, professional, and exactly what your customers should see.
Key features
Conditionals: Show or hide entire sections based on whether data exists or meets certain criteria.
Loops: Iterate over arrays like order items, product recommendations, or any list data.
Filters: Transform data on the fly with Twig’s built-in filters: uppercase, lowercase, date formatting, number formatting, and more.
Safe by Default: If there’s ever a Twig syntax error, the plugin logs it and sends the email anyway with the original content. Your transactional emails won’t fail silently.
GrapeJS Compatible: Works with Mautic’s visual email builder. The plugin automatically handles the HTML entity encoding that GrapeJS applies to special characters.
Installation
- Download the plugin from GitHub
- Rename the folder to
MauticTwigEnhancementsBundle - Upload to your Mautic
plugins/directory - Clear the cache:
php bin/console cache:clear - Go to Settings → Plugins → Install/Upgrade Plugins
That’s it. No configuration needed. The plugin automatically processes any Twig syntax in your emails.
Usage examples
Conditional content
The most common use case is showing content only when a variable exists:
{% if receipt_text is defined %}
<p>{{ receipt_text }}</p>
{% endif %}
You can also check for specific values:
{% if country == 'Jamaica' %}
<p>Free shipping to Jamaica!</p>
{% endif %}
Or use comparison operators:
{% if order_total > 100 %}
<p>You qualify for free shipping!</p>
{% else %}
<p>Add ${{ 100 - order_total }} more for free shipping.</p>
{% endif %}
Loops
Perfect for order confirmations with multiple items:
{% for item in items %}
<tr>
<td>{{ item.name }}</td>
<td>${{ item.price }}</td>
</tr>
{% endfor %}
Your API payload would include:
{
"items": [
{"name": "Airtime Top-up", "price": "5.00"},
{"name": "Data Bundle", "price": "10.00"}
]
}
Filters
Twig filters let you transform data inline:
{{ firstname|upper }} → JOHN
{{ email|lower }} → john@example.com
{{ order_date|date('F j, Y') }} → January 15, 2025
{{ price|number_format(2) }} → 1,234.56
{{ firstname|default('there') }} → "there" if firstname is empty
Working with MJML/GrapeJS
If you’re using Mautic’s GrapeJS email builder with MJML templates, there’s one important thing to know: you need to wrap Twig control structures in <mj-raw> tags.
This is because MJML compiles your template to HTML, and without <mj-raw>, the Twig tags get stripped out.
The pattern:
<mj-raw>{% if discount is defined and discount %}</mj-raw>
<mj-section>
<mj-column>
<mj-text>You saved {{ discount }}!</mj-text>
</mj-column>
</mj-section>
<mj-raw>{% endif %}</mj-raw>
Notice that {{ discount }} inside <mj-text> doesn’t need <mj-raw> – only the {% %} control structures need wrapping.
What needs wrapping:
{% if %}and{% endif %}{% for %}and{% endfor %}{% set %}and other control tags
What doesn’t need wrapping:
{{ variable }}output tags inside MJML components
API integration
When sending emails via Mautic’s API, pass your variables in the tokens object:
{
"email": 1,
"contact": 123,
"tokens": {
"order_id": "ORD-12345",
"order_total": 150.00,
"discount": "$10.00",
"items": [
{"name": "Product A", "price": 50.00},
{"name": "Product B", "price": 100.00}
]
}
}
These become available in your template as:
{{ order_id }}{{ order_total }}{{ discount }}{% for item in items %}
You can also access contact fields using {{ lead.firstname }} or {{ contact.email }}.
Error handling
One of the design principles of this plugin is that emails should never fail to send because of a template error.
If there’s a Twig syntax error in your template:
- The error is logged to Mautic’s log file
- The original template content is sent as-is
- Your customer still receives the email
Check var/logs/mautic_prod.log for any processing errors during development.
Comparison with advanced templates bundle
You might have seen the mautic-advanced-templates-bundle plugin. Here’s how this plugin differs:
| Feature | Advanced Templates | Twig Enhancements |
|---|---|---|
| Requires markers | Yes ({% TWIG_BLOCK %}) | No |
| Auto-processes all Twig | No | Yes |
| Mautic 6 support | Limited | Full |
| RSS feed support | Yes | No |
| Complexity | Higher | Lower |
This plugin is intentionally focused on the core use case: bringing Twig conditionals and loops to your emails without extra complexity.
Getting started
Here’s a quick checklist to get up and running:
- Install the plugin in your Mautic instance
- Create a new email or edit an existing one
- Add Twig syntax for your conditional content
- If using MJML, wrap control structures in
<mj-raw> - Test by sending via API with sample token data
- Check logs if something doesn’t render as expected
Conclusion
The Mautic Twig Enhancements plugin bridges the gap between Mautic’s simple token replacement and the complex conditional logic that real transactional emails require.
Whether you’re building receipt emails, order confirmations, shipping notifications, or any other data-driven email, having access to conditionals, loops, and filters makes your templates cleaner and more maintainable.
The plugin is open source and available on GitHub. Contributions, bug reports, and feature requests are welcome.