Throughout this article series, we have discussed many tools and methods that can help you to create maintainable email code. The most important concept is modularity. If you can decompose your monolith code, you already made a huge step.

A really good abstraction is when you think in components. If your component is general enough, does not include many hacks and you can use them as building blocks, then you are good to go.

Today, we are going to discuss some tools and technologies which will be your best friends in component-based email development.

Templating Languages

Most of you might have heard about templating languages and I guess many of you might have used them.

The typical usage is when you render something on the server side. The usual use-case is when you have to add dynamic content to your website, so when you fetch something from your database, you will have to replace some parts in your original template.

Besides that, you have basic control-flow in templating languages, for example, if branches and loops. These can help you to create a conditional rendering and to use the same sub-template multiple times. (Just think about a shopping cart, where you have to render multiple products. Their template can be the same, while the substituted data has to be different.)

The most popular templating languages that I know of and used are EJS, Handlebars, and Jade.

It's worth to mention, that in ES6 (the new standard for Javascript) there is a neat new feature called template strings. As you might have guessed, you can do the same trick with them as with templating languages. But which shall you use then? Don't worry, I will compare the two and talk about the pros and cons a little bit later.

Comparing Templating Languages and ES6 Template Strings

In this section, I am going to show you a short and easy to understand example implemented in EJS and with ES6 template strings.

I chose EJS because I have the most experience with that templating language. Also, it just adds to the original HTML syntax, so it's much more straightforward to me than Jade.

The example which I will show you is super simple. The page which we render will have a title and a list of products with prices. Each item will have different background-color, so we can easily navigate between the lines. It will look like this:

Simple shopping cart example

As you can see, it's super-simple. I am going to show you some complex examples with real email HTML, but for now, I want to keep things simple so everybody can have a solid basis before we plunge into the nasty email code.

The JSON data with which we feed the template to render our page is:

{
  "title": "My Email HTML Products",
  "products": [
    {
      "name": "Responsive Email Template",
      "price": 500
    },
    {
      "name": "Email Template Builder",
      "price": 2000
    },
    {
      "name": "HTML Generator",
      "price": 5000
    },
    {
      "name": "Drop Calc Generator",
      "price": 10000
    }
  ]
}

The EJS implementation looks like this:

<html>
    <head>
        <style>
            .even {
                background-color: #abcdef;
            }

            .odd {
                background-color: #fedcba;
            }

            .price {
                float: right;
            }
        </style>
    </head>
    <body>
        <h1><%= title %></h1>

        <div>
            <% for(let idx = 0; idx < products.length; idx +=1) { %>
                <% if(idx % 2 === 0) { %>
                <div class="even">
                <% } else { %>
                <div class="odd">
                <% } %>
                    <span><%= products[idx].name %></span>
                    <span class="price">$<%= products[idx].price %></span>
                </div>
            <% } %>
        </div>
    </body>
</html>

The same in Javascript with template strings:

function renderTemplate(data) {
    return `
    <html>
    <head>
        <style>
            .even {
                background-color: #abcdef;
            }
    
            .odd {
                background-color: #fedcba;
            }
    
            .price {
                float: right;
            }
        </style>
    </head>
    <body>
        <h1>${data.title}</h1>
    
        <div>
            ${
                data.products.map((item, idx) => {
                    const className = idx % 2 === 0 ? "even" : "odd";
                    return `
                        <div class="${className}">
                            <span>${item.name}</span>
                            <span class="price">$${item.price}</span>
                        </div>
                    `;
                }).join("")
            }
        </div>
    </body>
    </html>
    `;
}

Templating languages are great. Many people are most probably familiar with them already, so applying them to email development should not be a problem. Many of them are very well supported so you can enjoy syntax highlighting and many other neat features in text editors.

If you want to use templating languages (for example EJS), you have to use external libraries. To be honest, it can be a nightmare to debug these libraries. They hide many things from the developer. It's even impossible to use breakpoints, so you have to print every debug info to the output or the console if you want to debug something.

On the contrary, Javascript template strings are very, very easy to debug, because it's pure Javascript. You can use breakpoints and every other tool which you use for JS debugging.

You don't need dependencies because template strings is a built-in feature in modern Javascript.

My final argument is that template strings force you to use functional Javascript, for example, map, filter and reduce. If you master these features, you will be much, much more effective. You will write code faster and others who are familiar with these operations will understand your code in seconds.

Some people will not agree with me, but I think using Javascript's template strings is the way to go. What do you think about it?

Modularity with Javascript Template Strings

The previous example is obviously a monolith. Not a big one, but still... If you want to decompose it, you have to identify those parts which are logically separate from the other parts of the program.

If you want to define components properly, then they have to be context-free, which means, that these components must not depend on their parent's properties. In other words, it means that they will look the same no matter where you put them.

In our example above, we can define one component for the list items, one for the list itself and the main component, which includes the whole template.

After the decomposition, our product-list-item looks like this:

module.exports = function productListItem(item) {
    return `
        <div class="${item.className}">
            <span>${item.name}</span>
            <span class="price">$${item.price}</span>
        </div>
    `;
};

The product-list looks like this:

const productListItem = require("./product-list-item");

module.exports = function productList(products) {
    return products.map((item, idx) => {
        const className = idx % 2 === 0 ? "even" : "odd";

        return productListItem({
            className: className,
            name: item.name,
            price: item.price
        });
    }).join("");
};

And the main function is the following:

function renderTemplate(data) {
    return `
    <html>
    <head>
        <style>
            .even {
                background-color: #abcdef;
            }
    
            .odd {
                background-color: #fedcba;
            }
    
            .price {
                float: right;
            }
        </style>
    </head>
    <body>
        <h1>${data.title}</h1>
    
        <div>
            ${productList(data.products)}
        </div>
    </body>
    </html>
    `;
}

You can download the tutorial's full coding examples on Github

The example above is super simple, but it shows the basic concepts of decomposing a huge HTML template into smaller independent chunks. This is a great way to create reusable code.

Defining a Component System for Email Development

Following the methodology above, you can define the most basic components for HTML emails. Later, you can define complex ones based on the basic components.

The basic elements fall into two main categories: layout and content elements. The layout elements can have children whereas the content elements are usually terminal nodes, meaning they don't have any children, but they hold the information of the email itself.

Layout Elements

Layout elements can be called as container elements as well since they contain other elements. They can contain other containers and content elements as well. This way they define the document tree.

There are three main layout elements:

  • Centered containers: their main property is their width (which is usually 600px in HTML emails.
  • Multi-columns: you can put multiple columns next to each other.
  • Sections: They are simple containers to divide different parts of the document, for example, header, content, and footer. They can be used in other containers as well. If you define their background colors, you can emphasize the difference between such areas in your email.

With these three layout elements, you can create any kind of email layout with ease.

The usage of multi-columns is obvious, but let me explain something about sections and centered containers. You can combine them in two ways.

You can put sections into centered containers, where your sections will be the header, content, and footer. This is a very traditional way, the colored backgrounds of the sections will be 600px wide as their parent container is.

The other way you can combine them is when you put a centered container into a section. This way the sections background color will spread across the screen. You can put multiple stripes under each other (each stripe contains a section and a centered container within the section), and you will get a nice modern-looking email template.

Content Elements

These kinds of elements contain the content itself. They can be text elements, image elements, and buttons. I think most of the functionality related to them is obvious, but let me go into a little bit more detail about the text element.

In this categorization, text elements can contain some markup as well. For example header elements (<h1>, <h2>, <h3>, etc), list elements (<ul>, <ol>, <li>), and markdown which emphasizes some parts of the text (<i>, <strong>, etc).

You could create separate element types for the ones above, but in many cases, you'd create this part of your template with a WYSIWYG editor so you can use the output of that editor directly as the value of the text element. But if you feel like, you can define your own basic heading and list components. (I'm sure that you don't want to define separate components for bold, italic, etc since then you'd have to define text-node as well.)

The Benefit of Redefining Such Basic Elements

The best thing in a component system is that it's declarative. It means that you have to write down what you want to do, not how you want to do it.

Effectively, you don't have to deal with the implementation. Or you can even configure which implementation you want to use. For example you can generate a div or a table based email, depending on the email clients you have to support.

This kind of abstraction also helps you to separate the data from the visualization. Again, the HTML is hidden inside the implementation of the components. You just have to feed them with proper data, which is usually a JSON document.

Even though your document descriptor is a JSON, you can also define a markup language, which automatically translates to JSON. It means that instead of a JSON similar to this:

{
...
  "body": [
    {
      "type": "container",
      "children": [
        {
          "type": "section",
          "children": [
            {
              "type": "text",
              "tag": "p",
              "value": "Header"
            },
            {
              "type": "text",
              "tag": "p",
              "value": "Content"
            }
            {
              "type": "text",
              "tag": "p",
              "value": "Footer"
            }
          ]
        }
      ]
    }
  ]
...
}

you can write a much simpler markup, like this:

<eml>
  <body>
    <container>
      <section>
        <p>Header</p>
      </section>
      <section>
        <p>Content</p>
      </section>
      <section>
        <p>Footer</p>
      </section>
    </container>
  </body>
</eml>

If you want to write the code yourself, then you probably want to choose the latter, but if you need to do things programmatically, then the former might be more suitable for you.

You might have noticed that I used an <eml> tag in my second example. It stands for Email Markup Language, which I'm working on at the moment. I am very excited about it, it will contain tons of useful features for those who have to deal with HTML emails.

Complex Components

Based on the basic elements, you can define complex components. You can simply compose them to build up a complex one.

Just think about a hero unit component, which consists of an image, a title (which is a text element), a description (which is also a text element) and a call-to-action button.

Another example could be a product-list-item or a product-list, just as you saw in my very simple example.

Besides composing the atomic elements we already defined, you can create components with non-default functionality. Just think about interactive emails. There are multiple components, which can't be composed of our basic elements (for example a carousel, a tabbed pane or even prefilled forms).

Summary

In this article, you have learned about how to create reusable components for HTML emails with templating languages and Javascript template strings.

You also saw how to define a basic component system, which can be used as building blocks to create complex components.

This component system can be used to define a markup language to create responsive HTML emails. This is what I am secretly working on, so stay tuned, it will be released in the upcoming months.

Author
Gyula Németh

Gyula Németh

Co-founder & CTO @ EDMdesigner.com

  • 16 Command Examples to Send Email From The Linux Command Line 16 Command Examples to Send Email From The Linux Command Line

    In this post you'll learn how to send emails from the Linux command line. I'll show the most often used commands, SMTP configuration and terminal options.

    Read more
  • How to Create Responsive Email Designs with React Native How to Create Responsive Email Designs with React Native

    Responsive email coding is complex. Are you native in React Native? Abstract away email HTML & CSS into components with react-html-email or mjml frameworks.

    Read more
  • Using PHP for Sending HTML Emails with Mailgun, Sendgrid & Amazon SES Using PHP for Sending HTML Emails with Mailgun, Sendgrid & Amazon SES

    Ever wondered how to use PHP for sending HTML email templates with Mailgun, Sendgrid and Amazon SES? Read on for step-by-step coding advice.

    Read more