DEV Community

Cover image for Using MJML in Google Apps Script to Send Beautiful Emails

Using MJML in Google Apps Script to Send Beautiful Emails

Today I had the task of implementing a newsletter for internal updates and decided to use Google Apps Script since I was already using it for managing the project data. Based upon past experiences with emails using HTML I need this area was full of landmines and I didn't want to navigate through it. 💣

So I decided to use MJML with Google Apps Script.

mjml website screenshot

Overview of MJML

MJML is a markup language designed to reduce the pain of coding a responsive email. Its semantic syntax makes it easy and straightforward and its rich standard components library speeds up your development time and lightens your email codebase. MJML’s open-source engine generates high quality responsive HTML compliant with best practices.

The syntax looks like the following code snippet and has mechanisms for properly applying styles to the elements.

<mjml>
  <mj-body>
    <mj-section>
      <mj-column width="200px">
        <!-- First column content -->
      </mj-column>
      <mj-column width="400px">
        <!-- Second column content -->
      </mj-column>
    </mj-section>
  </mj-body>
</mjml>
Enter fullscreen mode Exit fullscreen mode

But what about the Apps Script Runtime! 😱

I wasn't sure what issues I was going to run into with the MJML compiler, but it actually wasn't that bad! My process went like this:

Note: I'm using Google Clasp and ESBuild.

  1. Try using the mjml package. Nope, tries to use Node's fs and path. ❌
  2. Try using the mjml-browser package. Success ✅

This requires me to give up some of the includes functionality, which didn't matter to me anyhow.

Since I'm using Google Clasp and ESBuild, the files in my project look like this:

apps script project files

My ESBuild file looks like the following, (note the platform: "node"):

await esbuild.build({
  entryPoints: ["./src/index.ts"],
  bundle: true,
  outdir,
  sourceRoot,
  platform: "node", // !! combining Node with mjml-browser
  format: "esm",
  plugins: [],
  inject: ["polyfill.js"],
  minify: true,
  banner: { js: "// Generated code DO NOT EDIT\n" },
  entryNames: "zzz_bundle_[name]",
  chunkNames: "zzz_chunk_[name]",
});

const passThroughFiles = ["main.js", "appsscript.json"];
Enter fullscreen mode Exit fullscreen mode

My Apps Script Code

I used the sample from https://mjml.io/try-it-live/templates/basic in my code and sent a test email to myself:

function main() {
  const { html } = mjml2html(
    `<mjml>
  <mj-body>
    ... OMITTED for brevity
  </mj-body>
</mjml>`
  );

  // send html email
  GmailApp.sendEmail(
    Session.getActiveUser().getEmail(), "Test", '', 
    { htmlBody: html });
}
Enter fullscreen mode Exit fullscreen mode

And it worked!

screenshot of the email

Conclusion

You can checkout the code in my Apps Script repository.

Test Release Changesets

Everything Apps Script

This repository is a monorepo containing tools, projects, and more related to Apps Script.






Next I need to publish a library, MJMLApp, that hides the gnarly bits! But for now I need to get back to that newsletter I need to send. 📤

Top comments (0)