If you ever tried to create responsive emails, you may have heard of MJML — the Mailjet Markup Language — supposedly “The only framework that makes responsive email easy”.

MJML provides a collection of reusable and extensible components, that allow you to build HTML email designs which are responsive by default and look great on all kinds of devices and email clients. MJML comes as an npm package, and provides a CLI or can be run directly from JavaScript code.

I’ve used MJML email templates with Ruby on Rails and was wondering if there’s something similar to the mjml-rails gem that I could use in an Elixir Phoenix app.

And indeed, there’s a hex package that provides a Phoenix Template Engine for MJML. However, the engine’s rendering flow is inverted. So I wasn’t able to create dynamic emails, because my EEx templates were not parsed until after the MJML transpiling. This means that all embedded Elixir is detected as invalid elements in the MJML components and the template creation fails altogether.

After fiddling around for a while with Phoenix Template Engines without success, I found another way to create dynamic MJML email templates in my app.

Here’s the setup that worked for me using Bamboo for sending emails:

  • add the mjmldependency to the project (npm, or hex NIF package)
  • render email templates (EEx) as usual
  • use the rendered email template as input for an additional MJML transpiling step
  • replace the HTML body content of the EEx rendering result with the transpiled MJML template

In a first step I tried using the mjml npm package, which left me with some performance questions. In a subsequent step I wrote the mjml Hex package that wraps an MJML Rust implementation as NIFs (Native Implemented Functions). Let’s look into the steps from above in detail and implement a working example — starting with the npm setup.


Adding MJML Support via the npm Package

First we add the mjml npm package to our Phoenix app’s package.json and install it with npm install (or yarn install, respectively):

// assets/package.json
	// ...

	  "dependencies": {
	    "phoenix": "file:../deps/phoenix",
	    "phoenix_html": "file:../deps/phoenix_html",
	    "mjml": "^4.6.3"
	  }
view raw
package.json hosted with ❤ by GitHub

Next we have to make sure, that we can run the MJML transpiling from Elixir. In order to do this, we set up a utility JavaScript file that we will run with the node executable later on. We will pass our rendered EEx template (still including MJML components) and we expect the transpiled final email HTML to be returned from it.

Let’s put a mjml.js into the Phoenix project’s bin/ directory:

// bin/mjml.js

	var {html: html} = require('../assets/node_modules/mjml')(process.argv[2]);
	console.log(html);
view raw
mjml.js hosted with ❤ by GitHub

The script takes an MJML string and prints the compiled HTML to the stdout. We require the mjml module and call it with the given MJML string. In the root directory of our Phoenix app, we can now already run the MJML transpiling with:

$ node bin/mjml.js "<mj-html></mj-html>"

#elixir #programming #email #html

Using MJML in Elixir & Phoenix
8.85 GEEK