Using custom web fonts in Maizzle email templates

Maizzle already makes it super easy to use Google Fonts in your email templates, but what if you need to use a custom web font?

Maybe your brand uses a custom type that isn't available through Google Fonts, or maybe you're just developing Shopify notification email templates (where the usual @import and <link> techniques aren't supported).

In this tutorial, you'll learn how to add your own custom fonts to emails in Maizzle.

Initial setup

First, make sure you have the Maizzle CLI installed.

We'll be using the default Maizzle starter, so let's start by creating a new project.

Open a terminal window and run the new command:

maizzle new

Follow the steps, using example-font-face as the folder name.

Once it finishes installing dependencies, open the folder in your favorite editor.

I use VS Code, so I'll do:

cd example-font-face && code .

Register @font-face

Imagine we have a display font called Barosan, which we're hosting on our website.

We'll use @font-face to register our custom font family - we can do this in the Template or in the Layout that we extend.

Add in Template

Open src/templates/transactional.html and add this before the <block name="template"> tag:

<block name="head">
  <style>
    @font-face {
      font-family: 'Barosan';
      font-style: normal;
      font-weight: 400;
      src: local('Barosan Regular'), local('Barosan-Regular'), url(https://example.com/fonts/barosan.woff2) format('woff2');
    }
  </style>
</block>

Using the default Starter, this will add a separate <style> tag in the compiled email HTML, right after the main one.

Add in Layout

If you prefer a single <style> tag in your email template, you can register the font in the Layout instead. Open src/layouts/master.html and replace this:

<if condition="page.css">
  <style>{{{ page.css }}}</style>
</if>

with this:

<if condition="page.css">
  <style>
    @font-face {
      font-family: 'Barosan';
      font-style: normal;
      font-weight: 400;
      src: local('Barosan Regular'), local('Barosan-Regular'), url(https://example.com/fonts/barosan.woff2) format('woff2');
    }
    
    {{{ page.css }}}
  </style>
</if>

Tailwind utility

Now that we're importing the font, we should register a Tailwind CSS utility for it.

Open tailwind.config.js, scroll down to fontFamily, and add a new font:

fontFamily: {
  barosan: [
    'Barosan',
    '-apple-system',
    '"Segoe UI"',
    'sans-serif',
  ],
  // sans: {}, etc...
}

Of course, you can change the other fonts in the stack. For example, display fonts often fallback to cursive.

Great! We're now ready to use the utility class in our email template.

Quick use

Simply add the font-baros class on every element where you want text to be rendered using your custom font.

For example, you can add it on a heading:

<h2 class="font-barosan">An article title</h2>

With CSS inlining enabled, that would result in:

<h2 style="font-family: Barosan, -apple-system, 'Segoe UI', sans-serif;">An article title</h2>

Advanced use

Repeatedly writing that font-barosan class on all elements isn't just impractical, it also increases HTML file size (especially when inlining), which then leads to Gmail clipping.

We can make use of Tailwind's screen variants and an Outlook font-family fallback to reduce bloat and write less code 👌

First, let's register a new @media query - we will call it screen:

// tailwind.config.js
module.exports = {
  theme: {
    screens: {
      screen: {'raw': 'screen'},
      sm: {'max': '600px'},
    },
  }
}

We can now use it on the outermost1 element:

<block name="template">
  <table class="screen:font-barosan">
    <!-- ... -->
  </table>
</block>

This will tuck the font-family away in an @media query:

/* Compiled CSS. Maizzle replaces escaped \: with - */
@media screen {
  .screen-font-barosan {
    font-family: Barosan, -apple-system, "Segoe UI", sans-serif !important;
  }
}

Since Outlook doesn't read @media queries, define a fallback2 for it in your Layout:

<!--[if mso]>
<style>
  td,th,div,p,a,h1,h2,h3,h4,h5,h6 {font-family: "Segoe UI", sans-serif;}
</style>
<![endif]-->

Outlook bugs

Custom fonts aren't supported in Outlook 2007-2016 - these email clients will fallback to Times New Roman. To avoid this, you can wrap the @font-face declaration in a @media query, so that Outlook will ignore it:

@media screen {
  @font-face {
    font-family: 'Barosan';
    font-style: normal;
    font-weight: 400;
    src: local('Barosan Regular'), local('Barosan-Regular'), url(https://example.com/fonts/barosan.woff2) format('woff2');
  }
}

Also, note that font-family isn't inherited on child elements in Outlook.

Extra weights

If your font comes with dedicated files for other weights, don't just slap font-bold on an element. Instead, import both the regular and bold versions of your font:

@font-face {
  font-family: 'Barosan';
  font-style: normal;
  font-weight: 400;
  src: local('Barosan Regular'), local('Barosan-Regular'), url(https://example.com/fonts/barosan.woff2) format('woff2');
}

@font-face {
  font-family: 'Barosan';
  font-style: normal;
  font-weight: 700;
  src: local('Barosan Bold'), local('Barosan-Bold'), url(https://example.com/fonts/barosan-bold.woff2) format('woff2');
}

Resources