DEV Community

Jan Dvorak
Jan Dvorak

Posted on

Html accounts e-mails in Meteor with mjml

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 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. First of all, we can adjust the url that the user gets send to. You can adjust that globally (on the server) like this:

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}`)
Enter fullscreen mode Exit fullscreen mode

Now to change the e-mail templates we need to operate inside of Meteor.startup function.

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

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

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:

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}`
    }
}
Enter fullscreen mode Exit fullscreen mode

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 and it is available as an npm package.

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 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:

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
}
Enter fullscreen mode Exit fullscreen mode

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:

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)
    }
}
Enter fullscreen mode Exit fullscreen mode

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 ❤️.

Top comments (0)