Dynamic content in your mails using Mustache

Alex Renoki
Jul 21, 2018 · 4 min read

While Laravel has its own way to render mails you will later send, i find Mustache as a better solution to the design & consitency problems:

  • It doesn’t use backend code inside your text block to render dynamic content. For most PHP devs, you don’t want to mix your PHP code in your HTML files, you should be using a template engine instead. Mustache kinda’ helps you organize content without mixing your backend code with your text.
  • Simple syntax. You can do if(…), if(!…), you can itereate through arrays, both associative arrays and flat arrays, and you have a simple syntax to display content, even for nested arrays.
  • It allows you to use any text. When you’re using Laravel, you are kind of limited to design, especially when you want a fresh, custom design. If you have your own mail templates, such as those created with MJML.io (i love to use MJML), BeeFree or any service like that, you may need to render custom content easier. Mustache handles this for you.

From my personal experience, i use MJML to write mails’ design and i mix it up with Mustache code. When i’m rendering it to HTML, i save the files and i then just get their content when i’m sending the mails.

Yes, that’s pretty old for me, but if you like to do this in an automate way, check out MJML repository where you can learn how to render your MJML files or you can use the MJML API that renders it for you via a REST API.


Mustache is an engine that is able to render content based on markdown. You can assign variables and then you can later display them in your block of text, for example. We will use it to create dynamic content for your users in newsletters.

To install Mustache, open your command line or add it to your Composer dependecies:

$ composer require mustache/mustache

Once it is installed, we can go to the next steps.


Let’s assume you have the following block of text, which you want to send your subscribers:

Hey, {{user.name}},
<br>
We have just launched, check out our new website.
<br>
{{webisteUrl}}
<br>
If you don't want to get in touch with us, you can <a href="{{unsubscribeUrl}}">unsubscribe</a> anytime.

Syntax is simple, right? I’m sure you have noticed are the variables in the double brackets. That is our markdown, so Mustache knows that there should be some variables passed by our code.

This text we can store it anywhere: files (so we can retrieve them later with file_get_contents(), for example), variables in the mid-processing or even database. We can later retrieve it and use it as our first argument in the method from the Mustache Engine class.

$mustache = new \Mustache_Engine;$renderedHtml = $mustache->render(
$request->text,
[
'websiteUrl' => env('APP_URL'),
'user' => $user->toArray(),
'unsubscribeUrl' => url('/unsubscribe?user={$user->id}'),
]
);

Mustache does the job for you: it reads the array and based on it, Mustache tries to match any markdown found in your text. If it’s a match, it just displays the value of the key from your array (passed as the second argument).

Rendering your text is one step away before sending the mail. You want to render your email before you send it, otherwise you’ll end up with {{variables}} all over the place, and your users won’t like it.

We assume that variable is an instance. Basically, passing models to your variables should be done using the method within the model. From Mustache perspective, this is how the variables array would look:

[
'websiteUrl' => env('APP_URL'),
'user' => [
'id' => 1
'name' => 'John',
],
'unsubscribeUrl' => url('/unsubscribe?user={$user->id}'),
]

If you have nested arrays, you can use the dot separator to access data, as you have seen in .


But what happens if you get to iterate arrays?

If you run newsletters for a shop, for example, you can provide an array and you can iterate it simply by using the before the array name.

{{#products}}
{{name}} - {{price}}
{{/products}}

In the variables array, you have to pass the array as associative.

$renderedHtml = $mustache->render($request->text,
[
'products' => [
[
'name' => 'Sunglasses',
'price' => '20 EUR',
],
...
]
]);

However, if you plan to send a plain array, you will have no key-value pairs. Instead, you will be using to address to the current iterated element in your arary.

If your variable is a boolean, you have markdoww for if statements, both for true or false:

{{#isPremiumMember}}
You have 10% discount!
{{/isPremiumMember}}
{{^isPremiumMember}}
Join membership and get discounts!
{{/isPremiumMember}}

To get more details, check the official documentation for Mustache Syntax and the PHP-version of the Mustache on GitHub. Also, check the Mustache official website if you plan to use it with other programming languages.

Alex Renoki

Written by

Certified Laravel Developer. Working with full-stack web applications, AWS, Kubernetes and buzzwords like cloud computing.