Html accounts e-mails in Meteor with mjml
Tags: meteor, javascript, tutorial, mjml
Published: 2021-02-24 08:50:40

So, you have build a nice looking app and are ready to conquer the world, but there is one hitch. When the e-mails go out they are just a plain text. Nothing wrong with that, but e-mails today. Now there are two big ways that we can deal with this in Meteor.

If you use Mailgun or other services like it to send out e-mails you might want to utilize the new `Email.hookSend` [hook](https://docs.meteor.com/api/email.html#Email-hookSend) from the Email package to intercept all user accounts e-mails that is being send by the accounts system and pass the url and receiver to a template via their API and design a template through their platform.

Now if you want to keep control or system like that isn't available you can adjust the e-mails in your Meteor app directly before they get send out.

Now let's take a look how to adjust things around accounts e-mails in Meteor. There are 3 e-mails that Meteor Accounts will send out. Reset password, account verification and account enrollment.

Let's get started with adjusting the Meteor's default [e-mail templates](https://docs.meteor.com/api/passwords.html#Accounts-emailTemplates). First of all, we can adjust the url that the user gets send to. You can adjust that globally (on the server) like this:

```javascript
import { Meteor } from 'meteor/meteor'
import { Accounts } from 'meteor/accounts-base'

Accounts.urls.resetPassword = token => Meteor.absoluteUrl(`user/reset-password/${token}`)
Accounts.urls.verifyEmail = token => Meteor.absoluteUrl(`user/verify-email/${token}`)
Accounts.urls.enrollAccount = token => Meteor.absoluteUrl(`user/enroll/${token}`)
```

Now to change the e-mail templates we need to operate inside of `Meteor.startup` [function](https://docs.meteor.com/api/core.html#Meteor-startup).

First of all we can change the e-mail headers globally like this:

```javascript
Accounts.emailTemplates.siteName = 'Awesome site'
Accounts.emailTemplates.from = 'Awesome site no-reply <no-reply@awesome.universe>'
Accounts.emailTemplates.headers = { tag: 'my-awesome-emails' }
```

Now to adjust the 3 different templates we can set `Accounts.emailTemplates.enrollAccount`, `Accounts.emailTemplates.resetPassword` and `Accounts.emailTemplates.verifyEmail`. In these we can set `from`, `subject`, `text` and `html`. Now since, we have already set the global `from` earlier we can skip this.

So the basic would look like this:
```javascript
Accounts.emailTemplates.resetPassword = {
    subject (user) {
      return `Reset password for ${user.username}`
    },
    text (user, url) {
      return `Hello ${user.username}!\n\n We have received a request to reset your password for your account.
        Please follow the link below to reset your password:\n\n${url}`
    }
}
```

Now these are self explanatory, but what about html e-mails and how do they work? With the html e-mails you can pass in a string that is an html, if it is present and the user's e-mail client supports displaying html e-mails it will take precedent and display the html message, otherwise the text message will be displayed.

The problem with html messages is the same like with mobile design for your app. As such it is recommended to use some sort of a framework to help with this to ensure that the e-mails are nicely formatted in all circumstance. One of the most common tools for this is [mjml](https://mjml.io/) and it is available as an [npm package](https://www.npmjs.com/package/mjml).

For our 3 e-mails it is probably a good idea to create a template so that they have the general look. My personal recommendation is to go to the official website, select a [template](https://mjml.io/templates) to start from and adjust it to your needs using their editor to make sure that your mjml is valid.

Once you have a nice template ready it is time to implement it. This is my template function:

```javascript
import mjml2html from 'mjml'

export const htmlEmailTemplate = (title, message) => {
  return mjml2html(`
    <mjml>
      <mj-head>
        <mj-title>{title}</mj-title>
      </mj-head>
      <mj-body background-color="#efefef">
        <mj-section background-color="#fff" padding-bottom="0px" padding-top="0">
          <mj-column vertical-align="top" width="100%">
            <mj-image
                src="https://files.awesome.site/logo.png"
                alt="logo"
                align="center"
                border="none"
                width="600px"
                padding-left="0px"
                padding-right="0px"
                padding-bottom="0px"
                padding-top="0"
            ></mj-image>
          </mj-column>
        </mj-section>
        ${message}
      </mj-body>
    </mjml>
  `)?.html
}
```

Please do note the `.html` at the end of the function as mjml will return an object that also includes any errors that have occurred while generating the e-mail. For now we are just getting the html sting without checking for the errors. Finally we can adjust our reset password template by adding the html field:

```javascript
Accounts.emailTemplates.resetPassword = {
    subject (user) {
      return `Reset password for ${user.username}`
    },
    text (user, url) {
      return `Hello ${user.username}!\n\n We have received a request to reset your password for your account.
        Please follow the link below to reset your password:\n\n${url}`
    },
    html (user, url) {
      const title = `Reset password for ${user.username}`
      const message = `
        <mj-section background-color="#4a148c" padding-bottom="0px" padding-top="0">
          <mj-column vertical-align="top" width="100%">
            <mj-text align="left" color="#ffffff" font-size="45px" font-weight="bold" font-family="open Sans Helvetica, Arial, sans-serif" padding-left="25px" padding-right="25px" padding-bottom="30px" padding-top="50px">
              Reset password
            </mj-text>
          </mj-column>
        </mj-section>
        <mj-section background-color="#4a148c" padding-bottom="20px" padding-top="20px">
          <mj-column vertical-align="middle" width="100%">
            <mj-text align="left" color="#ffffff" font-size="22px" font-family="open Sans Helvetica, Arial, sans-serif" padding-left="25px" padding-right="25px">
              <span style="color:#FEEB35">Hello ${user.username}!</span>
            </mj-text>
            <mj-text align="left" color="#ffffff" font-size="15px" font-family="open Sans Helvetica, Arial, sans-serif" padding-left="25px" padding-right="25px">
              You dooped! But fear not reset your password by clicking on the button bellow:
            </mj-text>
            <mj-button
                align="left"
                font-size="22px"
                font-weight="bold"
                background-color="#ffffff"
                border-radius="10px"
                color="#1AA0E1"
                font-family="open Sans Helvetica, Arial, sans-serif"
                href="${url}"
            >
              Reset password
            </mj-button>
            <mj-text align="left" color="#ffffff" font-size="15px" font-family="open Sans Helvetica, Arial, sans-serif" padding-left="25px" padding-right="25px">
              Sincerely, the team
            </mj-text>
          </mj-column>
        </mj-section>
      `
      return htmlEmailTemplate(title, message)
    }
}
```

And now we have a nice looking html e-mails going out from our system. You can then use `htmlEmailTemplate` function for other `Email.send` functionality.

--------
If you like my work, please consider supporting me on [GitHub Sponsors ❤️](https://github.com/sponsors/StorytellerCZ).