email-builder

A build tool for emails

Usage no npm install needed!

<script type="module">
  import emailBuilder from 'https://cdn.skypack.dev/email-builder';
</script>

README

Email Builder

Overview

Email Builder assists in the creation of html emails. This tool aims to simplify tedious and manual tasks with the following features:

  • Compilation of "layouts", "templates" and "partials" using Handlebars
    • "Layouts" serve as a blueprint of an email. They provide the ability to create a predefined structure for an email.
    • "Templates" can be thought of as the scaffolding of an email. They are used to compose a mix of simple, static content and reusable partials.
    • "Partials" are chunks of html that can be included within a template. A common example is a header at the top of an email. Partials are intended to be reusable.
  • Loading and in-lining CSS from external stylesheets using Juice. This feature of the tool allows for stylesheets to be shared among email projects and more easily maintained.
  • HTML formatting via Pretty so that the resulting email markup is valid and readable.

Quick Start

  • Install Email Builder via NPM:
npm install -g email-builder
  • Create a config.json file in the root directory of your project. See the "Configuration" section for details.
  • Build your emails:
email-builder --config ./config.json
  • Your html files will be output of the outputPath specified in your config file.

How it works

The Email Builder is installed via NPM and is interacted with via the command line. A single command is used to build emails and, once installed, there is very little that the user needs to be concerned with in order to use the tool.

Once the user has Email Builder running on their machine they can use it within any folder/directory, including connected drives and servers.

Configuration

Within the folder of your email project, you will have a single configuration file that contains the information that the email builder needs in order to compile your project. The file is created in JSON format which is very simple to read and edit. Here’s a full example of a configuration file:

{
  "sourcePath": "/path/to/your/email/assets",
  "outputPath": "/path/to/your/built/emails",
  "emails": {
    "hello": {
      "template": "./templates/hello.hbs",
      "partials": [
        "./layouts/default.hbs",
        "./partials/header.hbs"
      ],
      "styles": [
        "./styles/default.css",
        "./styles/hello.css"
      ],
      "context": {
        "title": "Howdy!",
        "heroHeadline": "An awesome, short headline",
        "heroCTA": {
          "text": "Learn More",
          "href": "http://google.com"
        }
      }
    }
  }
}

Configuration Options

sourcePath

This setting tells Email Builder where to look for your email assets (template files, partial files, etc.)

outPath

A path to a folder where you want the fully built emails to be output.

emails

This is a list of each email you will be building in this project. This can be one or many emails. Each email has a name which will be the filename of the generated email. In the example above, the name is “hello”.

emails.styles

The CSS stylesheets for this email. CSS files listed here will be read by Email Builder and automatically inlined into your html. For example:

This stylesheet content…

.hero {
  background: #00c3ff;
  color: white;
  width: 100%;
}

.hero > tr > td {
  padding: 20px;
}

Will be added to your html during the build like so…

<table class="hero" style="font-size: 15px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background: #00c3ff; color: white; width: 100%;" width="100%">
  <tr>
    <td style="padding: 20px;">
      <h1>A short headline</h1>
    </td>
  </tr>
</table>

emails.template

Specifies the template file for this email. This path is relative to the sourcePath. In other words, if your template exists at /full/path/to/template/hello.hbs and your sourcePath is set to /full/path/to/, your template path would be ./template/hello.hbs.

emails.partials

A list of partials that this email will use. Like emails.template, this path is relative to your sourcePath.

emails.context

This is "contextual” data that can be passed to the template or partials, allowing for dynamic content population during the build. In our example, we include a property called heroHeadline and provide a value. To use this value, you would simply include {{ heroHeadline }} within your template and the value would be populated. Example:

Config (json):

context: {
    heroHeadline: "A nifty headline!"
}

Template (hbs/handlebars):

<tr>
    <td>
        <h1>{{ heroHeadline }}</h1>
    </td>
</tr>

You can use as many context variables as needed.

HTML Output

The resulting html after being compiled by Email Builder is output based on your “outPath” setting and the name of each email. Referring to our example configuration, the resulting file would be “/path/to/your/built/emails/hello.html”. This document html is ready for delivery.

Example

The following shows a complete example of a project which utilizes Email Builder.

The configuration file:

{
  "sourcePath": "/Users/jhulbert/WebServer/_sandbox/email-builder/examples",
  "outputPath": "/Users/jhulbert/WebServer/_sandbox/email-builder/dist",
  "emails": {
    "hello": {
      "template": "./templates/hello.hbs",
      "partials": [
        "./partials/header.hbs",
        "./partials/hero.hbs",
        "./partials/body.hbs"
      ],
      "styles": [
        "./styles/hello.css"
      ],
      "context": {
        "title": "Howdy!",
        "heroHeadline": "An awesome, short headline",
        "heroCTA": {
          "text": "Learn More",
          "href": "http://google.com"
        }
      }
    }
  }
}

The html template (“hello.hbs”):

<html>
  <head>
    <title>{{ title }}</title>
    <meta name="viewport" content="initial-scale=1,width=device-width" />
  </head>
  <body>
    <table class="wrap">
      <tr>
        <td>
          {{> header }}
        </td>
      </tr>
      <tr>
        <td>
          {{> hero}}
        </td>
      </tr>
      <tr>
        <td>
          {{> body}}
        </td>
      </tr>
    </table>
  </body>
</html>

The html partials:

header.hbs

<table class="header">
  <tr>
    <td>
      Brand Header
    </td>
  </tr>
</table>

hero.hbs

<table class="hero">
  <tr>
    <td>
      <h1>{{ heroHeadline }}</h1>
    </td>
  </tr>
  <tr>
    <td>
      <a href="{{ heroCTA.href }}">{{ heroCTA.text }}</button>
    </td>
  </tr>
</table>

body.hbs

<table class="body">
  <tr>
    <td>
      <p> Maecenas hendrerit sodales vestibulum. Donec lorem tellus, gravida sit amet ligula id, ultrices facilisis tellus. Suspendisse porttitor arcu id accumsan malesuada. Aliquam iaculis aliquam eros sit amet interdum. Donec dictum cursus lacus, nec malesu…</p>
    </td>
  </tr>
</table>

The “hello.css” stylesheet:

body {
  background-color: #ebebeb;
}

body,
table {
  font-size: 15px;
  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

p, ul, ol, dl {
  line-height: 1.5;
}

.wrap {
  background-color: #fff;
  width: 640px;
  margin: 0 auto;
  border-collapse: collapse;
}

.wrap > tr > td {
  padding: 0;
}

.header {
  color: #fff;
  background-color: #000;
  width: 100%;
}

.header > tr > td {
  padding: 10px 20px;
}

.hero {
  background: #00c3ff;
  color: white;
  width: 100%;
}

.hero > tr > td {
  padding: 20px;
}

.body > tr > td {
  padding: 20px;
}

Email output:

When processed, the above configuration will output the following html:

<html>
  <head>
    <title>Howdy!</title>
    <meta name="viewport" content="initial-scale=1,width=device-width">
  </head>
  <body style="background-color: #ebebeb; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;">
    <table class="wrap" style="font-size: 15px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background-color: #fff; width: 640px; margin: 0 auto; border-collapse: collapse;" width="640" bgcolor="#fff">
      <tr>
        <td style="padding: 0;">
          <table class="header" style="font-size: 15px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; color: #fff; background-color: #000; width: 100%;" width="100%" bgcolor="#000">
            <tr>
              <td style="padding: 10px 20px;">
                Brand Header
              </td>
            </tr>
          </table>
        </td>
      </tr>
      <tr>
        <td style="padding: 0;">	
          <table class="hero" style="font-size: 15px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; background: #00c3ff; color: white; width: 100%;" width="100%">
            <tr>
              <td style="padding: 20px;">
                <h1>An awesome, short headline</h1>
              </td>
            </tr>
            <tr>
              <td style="padding: 20px;">
                <a href="http://google.com">Learn More
                </a>
              </td>
            </tr>
          </table>
        </td>
      </tr>
      <tr>
        <td style="padding: 0;">
          <table class="body" style="font-size: 15px; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;">
            <tr>
              <td style="padding: 20px;">
                <p style="line-height: 1.5;">Maecenas hendrerit sodales vestibulum. Donec lorem tellus, gravida sit amet ligula id, ultrices facilisis tellus. Suspendisse porttitor arcu id accumsan malesuada. Aliquam iaculis aliquam eros sit amet interdum. Donec dictum cursus lacus, nec malesu…</p>
  </td>
            </tr>
          </table>
        </td>
      </tr>
    </table>
  </body>
</html>