Code Monkey home page Code Monkey logo

mjml_eex's Introduction

MJML EEx Logo

Easily create beautiful emails using MJML right from Elixir!

Hex.pm GitHub Workflow Status (master) Coveralls master branch Support the project


Contents

Installation

Available in Hex, the package can be installed by adding mjml_eex to your list of dependencies in mix.exs:

def deps do
  [
    {:mjml_eex, "~> 0.10.0"}
  ]
end

Documentation can be found at https://hexdocs.pm/mjml_eex.

Supporting MJML EEx

If you rely on this library to generate awesome looking emails for your application, it would much appreciated if you can give back to the project in order to help ensure its continued development.

Checkout my GitHub Sponsorship page if you want to help out!

Gold Sponsors

Support the project

Silver Sponsors

Support the project

Bronze Sponsors

Support the project

Using MJML EEx

Basic Usage

Add {:mjml_eex, "~> 0.7.0"} to your mix.exs file and run mix deps.get. After you have that in place, you can go ahead and create a template module like so:

defmodule BasicTemplate do
  use MjmlEEx, mjml_template: "basic_template.mjml.eex"
end

And the accompanying MJML EEx template basic_template.mjml.eex (note that the path is relative to the calling module path):

<mjml>
  <mj-body>
    <mj-section>
      <mj-column>
        <mj-divider border-color="#F45E43"></mj-divider>
        <mj-text font-size="20px" color="#F45E43"
          >Hello <%= @first_name %> <%= @last_name %>!</mj-text
        >
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

With those two in place, you can now run BasicTemplate.render(first_name: "Alex", last_name: "Koutmos") and you will get back an HTML document that can be emailed to users.

Using Functions from Template Module

You can also call functions from your template module if they exist in your MJML EEx template using the following module declaration:

defmodule FunctionTemplate do
  use MjmlEEx, mjml_template: "function_template.mjml.eex"

  defp generate_full_name(first_name, last_name) do
    "#{first_name} #{last_name}"
  end
end

In conjunction with the following template:

<mjml>
  <mj-body>
    <mj-section>
      <mj-column>
        <mj-divider border-color="#F45E43"></mj-divider>
        <mj-text font-size="20px" color="#F45E43"
          >Hello <%= generate_full_name(@first_name, @last_name) %>!</mj-text
        >
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

In order to render the email you would then call: FunctionTemplate.render(first_name: "Alex", last_name: "Koutmos")

Using Components

In addition to compiling single MJML EEx templates, you can also create MJML partials and include them in other MJML templates AND components using the special render_static_component function. With the following modules:

defmodule FunctionTemplate do
  use MjmlEEx, mjml_template: "component_template.mjml.eex"
end
defmodule HeadBlock do
  use MjmlEEx.Component

  @impl true
  def render(_opts) do
    """
    <mj-head>
      <mj-title>Hello world!</mj-title>
      <mj-font name="Roboto" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500"></mj-font>
    </mj-head>
    """
  end
end

And the following template:

<mjml>
  <%= render_static_component HeadBlock %>

  <mj-body>
    <mj-section>
      <mj-column>
        <mj-divider border-color="#F45E43"></mj-divider>
        <mj-text font-size="20px" color="#F45E43"
          >Hello <%= generate_full_name(@first_name, @last_name) %>!</mj-text
        >
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>

Be sure to look at the MjmlEEx.Component module for additional usage information as you can also pass options to your template and use them when generating the partial string. One thing to note is that when using render_static_component, the data that is passed to the component must be defined at compile time. This means that you cannot use any assigns that would bee to be evaluated at runtime. For example, this would raise an error:

<mj-text>
  <%= render_static_component MyTextComponent, some_data: @some_data %>
</mj-text>

If you need to render your components dynamically, use render_dynamic_component instead and be sure to configure your template module like so to generate the email HTML at runtime:

def MyTemplate do
  use MjmlEEx, mode: :runtime
end

Using Layouts

Often times, you'll want to create an Email skeleton or layout using MJML, and then inject your template into that layout. MJML EEx supports this functionality which makes it really easy to have business branded emails application wide without having to copy and paste the same boilerplate in every template.

To create a layout, define a layout module like so:

defmodule BaseLayout do
  use MjmlEEx.Layout, mjml_layout: "base_layout.mjml.eex"
end

And an accompanying layout like so:

<mjml>
  <mj-head>
    <mj-title>Say hello to card</mj-title>
    <mj-font
      name="Roboto"
      href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500"
    ></mj-font>
    <mj-attributes>
      <mj-all font-family="Montserrat, Helvetica, Arial, sans-serif"></mj-all>
      <mj-text
        font-weight="400"
        font-size="16px"
        color="#000000"
        line-height="24px"
      ></mj-text>
      <mj-section padding="<%= @padding %>"></mj-section>
    </mj-attributes>
  </mj-head>

  <%= @inner_content %>
</mjml>

As you can see, you can include assigns in your layout template (like @padding), but you also need to include a mandatory @inner_content expression. That way, MJML EEx knowns where to inject your template into the layout. With that in place, you just need to tell your template module what layout to use (if you are using a layout that is):

defmodule MyTemplate do
  use MjmlEEx,
    mjml_template: "my_template.mjml.eex",
    layout: BaseLayout
end

And your template file can contain merely the parts that you need for that particular template:

<mj-body> ... </mj-body>

Configuration

MJML EEx has support for both the 1st party NodeJS compiler and the 3rd party Rust compiler. By default, MJML EEx uses the Rust compiler as there is an Elixir NIF built with Rustler that packages the Rust library for easy use: mjml_nif. By default the Rust compiler is used as it does not require you to have NodeJS available.

In order to use the NodeJS compiler, you can provide the following configuration in your config.exs file:

config :mjml_eex, compiler: MjmlEEx.Compilers.Node

Be sure to check out the documentation for the MjmlEEx.Compilers.Node module as it also requires some additional set up.

Attribution

  • The logo for the project is an edited version of an SVG image from the unDraw project
  • The Elixir MJML library that this library builds on top of MJML
  • The Rust MRML library that provides the MJML compilation functionality MRML

mjml_eex's People

Contributors

akoutmos avatar dvic avatar kianmeng avatar paridin avatar petermm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

mjml_eex's Issues

elixir compile-time mjml compiler execution

Hi, thanks for this library, MJML looks very promising.

I've noticed that https://github.com/jdrouet/mrml has been archived, thus I'm leaning towards the npm cli tool. Regardless, do you think it would be possible to stitch it together so that the actual MJML binary process execution is done only at build-time on the elixir end?

Spawning OS processes under production workload feels sub-optimal and I'm wondering if there's any room for compile-time pipeline. I suppose the biggest issue is the EEx integration, since when you embed EEx markup inside MJML, it'll swallow it:

$ echo "<mjml>
    <mj-body>
      <mj-section>
        <mj-column>
          <%= for x <- @items do %><mj-text>
            <%= x.data %>
          </mj-text><% end %>
        </mj-column>
      </mj-section>
    </mj-body>
  </mjml>" | assets/node_modules/mjml/bin/mjml -i | grep for

Do you think there's a way to get around it? I'd be happy to work on a PR.

Using EEx inside components?

Is there a way to insert EEx inside components, just like we do in templates?

I've only seen the option to pass opts to a dynamic component and then use string interpolation, but it looks like we can't use EEx inside a component, right?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.