Dynamic emails with handlebars and nodemailer
Tags: productivity, node, nodemailer
Published: 2023-02-10 16:11:39

Ever tried writing a dynamic email in HTML & CSS? If so, did you like it? Probably not.

It’s a dreaded task that we’d love to pass on to marketing. Or anyone for that matter. 

But sometimes it’s not possible. So we decided to hack something together that might make it *slightly* less painful to draft emails with variables - especially transactional emails. 

We hope it means you get a MailChimp-like experience without using MailChimp.

Demo URL: [https://handlebars-email-html-previewer.vercel.app/](https://handlebars-email-html-previewer.vercel.app/)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oex97jnra5210ht3n44a.gif)


The preview app does three main things:

1. Let’s you draft/modify a HTML template with variables containing handlebars & instantly preview it in the browser
2. Put some test variables into JSON to see that they’re working
3. Send a test email to Mailtrap 

*Note: right now we don’t save your template anywhere but we plan to implement this later. For now, copy-paste and don’t close the tab!*

You can see the [client code here](https://github.com/nsmet/handlebars-email-html-previewer) and the [server code that connects with Mailtrap here](https://github.com/nsmet/mailtrap-node-relay).

## How we built the Editor

We wanted to have a nice coding experience in the browser so we tried out a ton of different packages including:

- [React Ace Editor](https://www.npmjs.com/package/react-ace)
- [React Textarea Code Editor](https://uiwjs.github.io/react-textarea-code-editor/)
- [React Simple Code Editor](https://www.npmjs.com/package/react-simple-code-editor)

But we found them all either difficult to work with, outdated or a bit laggy for us. They’re probably all great but we didn’t have time so we moved on if we couldn’t get it working smoothly quickly.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/da2k66qursebmnufjp12.gif)



Finally, I came across a comment on Reddit suggesting [Monaco](https://github.com/react-monaco-editor/react-monaco-editor) because VSCode is built on top of it.

Monaco  worked perfectly out the box (except for a tiny bit of flashing when you type)


It also had some really nice advanced features like autocomplete and a map view.

It was also really easy to implement. 

```tsx
import Editor from "@monaco-editor/react";

interface Props {
    code: string;
    onChange: (code: string) => void;
}

function MyEditor(props: Props) {
  return (
      <Editor
          value={props.code}
          language="handlebars"
          defaultValue="Please enter HTML code."
          theme="vs-dark"
          onChange={(newvalue?: string) => props.onChange(newvalue || '')}
      />
  );
}

export default MyEditor;
```

It pretty much works the same as a text box where you update the state on change.

As you can see we also changed it to dark mode 😎


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xxh1dqgl23mwvep7i6ju.gif)


## Using Handlebars to add variables

Handlebars are commonly used in HTML emails to make them dynamic. You can use it like so 

```tsx
Your HTML code
...
<p>{{name}}</p>
...
```

The opening and closing brackets indicate a handlebar variable, more information can be found [here](https://handlebarsjs.com/).

Then we use the Handlebars compiler to turn our HTML with handlebars variables, to plain HTML with inserted variables. 

```tsx
import Handlebars from 'handlebars';
const data = {
	name: "John"
}

const handlebarsTemplate = Handlebars.compile(YOUR_HTML);
const parsedHtml = handlebarsTemplate(data);

// this transforms the code to 
...
<p>John</p>
...
```

Handlebars is quite powerful. You can add in conditional logic, loops, etc…


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uzvycpbu8vh1wicv95a9.gif)


## Previewing the email

But now, the tricky part! How do you know your handlebars actually work with the given data? 

That was the whole reason we made this tool, easy validation of our handlebar templates with live previews. 

On each code change we update your live preview, so you can see exactly how your code looks, and behaves.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/psnzwd9hynwjyi32q4vh.gif)



We also provided a way of inputting test data. Click on the top right corner on “set test data”. This will open up a JSON editor. Here you can add the variables you declared in your HTML template with handlebars, alongside their test data values.

For instance if you have a variable `{{name}}` in your HTML template, you can create JSON test data like this:

```json
{
    "name":"Satoshi Nakamoto"
}
```

## Sending test emails to Mailtrap

The final feature of this tool allows you to send your preview to your Mailtrap inbox. This is important because the browser preview is not always going to be perfectly accurate. 

Click on “Mailtrap” in the top right corner, this will open up the config modal. 

You’ll be asked for:

- **Inbox ID:** This can be found in the url when you open up your inbox in Mailtrap
- **Api Key:** Can be found under settings → API keys in Mailtrap

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e8avcdnn7p8nlnf33d2a.gif)


You only need to input these once, it will be stored in local storage for easy use afterwards 

Then go ahead and click “send test email”! This will send a test email to your mailtrap using a small node application we made ([which can be found here](https://github.com/nsmet/mailtrap-node-relay)). We use this small node server to avoid CORS errors, the only purpose is to take your HTML, and send a request to the mailtrap API.

## **Further info**

We didn’t focus on how to send emails with nodemailer. There are a lot of tutorials out there, here are some suggestions:

- [https://dev.to/lo_victoria2666/how-to-build-a-contact-form-with-javascript-and-nodemailer-3i1k](https://dev.to/lo_victoria2666/how-to-build-a-contact-form-with-javascript-and-nodemailer-3i1k)
- [https://dev.to/search?q=nodemailer](https://dev.to/search?q=nodemailer)
- [https://dev.to/jlong4223/how-to-implement-email-functionality-with-node-js-react-js-nodemailer-and-oauth2-2h7m](https://dev.to/jlong4223/how-to-implement-email-functionality-with-node-js-react-js-nodemailer-and-oauth2-2h7m)