Skip to main content

Template Adapters

Each adapter wraps a template engine and provides a consistent interface for compiling email templates.

Import paths

Adapters are imported from @nestjs-modules/mailer/adapters/<name>.adapter. The legacy @nestjs-modules/mailer/dist/adapters/<name>.adapter paths used by 2.0.x remain supported for backwards compatibility.

Handlebars​

import { HandlebarsAdapter } from '@nestjs-modules/mailer/adapters/handlebars.adapter';

MailerModule.forRoot({
// ...
template: {
dir: __dirname + '/templates',
adapter: new HandlebarsAdapter(),
options: { strict: true },
},
})

Custom Helpers​

Pass a helpers object to the adapter:

const helpers = {
uppercase: (value: string) => value.toUpperCase(),
formatDate: (date: Date) => date.toLocaleDateString(),
};

new HandlebarsAdapter(helpers);

Partials​

Enable Handlebars partials for reusable template fragments:

import * as path from 'node:path';

MailerModule.forRoot({
// ...
template: {
dir: path.join(process.env.PWD, 'templates/pages'),
adapter: new HandlebarsAdapter(),
options: { strict: true },
},
options: {
partials: {
dir: path.join(process.env.PWD, 'templates/partials'),
options: { strict: true },
},
},
})

Pug​

import { PugAdapter } from '@nestjs-modules/mailer/adapters/pug.adapter';

MailerModule.forRoot({
// ...
template: {
dir: __dirname + '/templates',
adapter: new PugAdapter(),
options: { strict: true },
},
})

template.options are passed to pug's compiler (for example basedir, pretty or filters) and are also available as template variables. Since 3.0, the context only provides template variables and can no longer change compiler options.

EJS​

import { EjsAdapter } from '@nestjs-modules/mailer/adapters/ejs.adapter';

MailerModule.forRoot({
// ...
template: {
dir: __dirname + '/templates',
adapter: new EjsAdapter(),
options: { strict: true },
},
})

Liquid​

import { LiquidAdapter } from '@nestjs-modules/mailer/adapters/liquid.adapter';

MailerModule.forRoot({
// ...
template: {
dir: __dirname + '/templates',
adapter: new LiquidAdapter(),
},
})

MJML​

MJML creates responsive emails. The MjmlAdapter wraps another template adapter (Pug, Handlebars, or EJS) to compile your template first, then convert the output through MJML into responsive HTML.

Important: Set inlineCssEnabled: false because MJML handles its own CSS inlining.

import { MjmlAdapter } from '@nestjs-modules/mailer/adapters/mjml.adapter';

// With Handlebars
new MjmlAdapter('handlebars', { inlineCssEnabled: false })

// With Pug
new MjmlAdapter('pug', { inlineCssEnabled: false })

// With EJS
new MjmlAdapter('ejs', { inlineCssEnabled: false })

You can also pass Handlebars helpers via the third parameter:

new MjmlAdapter(
'handlebars',
{ inlineCssEnabled: false },
{ handlebar: { helper: myHelpers } },
)

CSS Inlining​

All default adapters support built-in CSS inlining via css-inline. Control it through the adapter config:

// Enable with custom options
new HandlebarsAdapter(undefined, {
inlineCssEnabled: true,
inlineCssOptions: {
// See: https://www.npmjs.com/package/@css-inline/css-inline#configuration
},
});

// Disable CSS inlining
new EjsAdapter({
inlineCssEnabled: false,
});

new PugAdapter({
inlineCssEnabled: true,
inlineCssOptions: {},
});

Remote Stylesheets​

Since 3.0, CSS inlining never fetches stylesheets: loadRemoteStylesheets defaults to false, even when you pass your own inlineCssOptions. Local <link rel="stylesheet"> tags are resolved by the Handlebars and EJS adapters, and only .css files inside the template directory (or cssBaseUrl) are read. Any other <link> is dropped.

Opt back in only if your templates never contain URLs that come from user data:

new HandlebarsAdapter(undefined, {
inlineCssOptions: { loadRemoteStylesheets: true },
});