Email templates
Create, preview, and send custom Node.js email templates. Automatic inline ...
README
[Email Templates](https://github.com/forwardemail/email-templates)
Table of Contents
Install
By default we recommend [pug][] for your template engine, but you can use [any template engine][supported-engines].
- ```sh
- npm install email-templates pug
- ```
Preview
Usage
Debugging
Environment Flag
- ```sh
- NODE_DEBUG=email-templates node app.js
- ```
Inspect Message
- ``` js
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- name: 'Elon'
- }
- })
- .then(res => {
- console.log('res.originalMessage', res.originalMessage)
- })
- .catch(console.error);
- ```
Basic
You can swap the transport option with a [Nodemailer transport][nodemailer-transport] configuration object or transport instance. We highly recommend using [Postmark][] for your transport (it's the default in [Lad][]).
If you want to send emails in development or test environments, set options.send to true.
- ``` js
- const Email = require('email-templates');
- const email = new Email({
- message: {
- from: 'test@example.com'
- },
- // uncomment below to send emails in development/test env:
- // send: true
- transport: {
- jsonTransport: true
- }
- });
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- name: 'Elon'
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
- ```sh
- .
- ├── app.js
- └── emails
- └── mars
- ├── html.pug
- └── subject.pug
- ```
html.pug:
- ```pug
- p Hi #{name},
- p Welcome to Mars, the red planet.
- ```
subject.pug:
- ```pug
- = `Hi ${name}, welcome to Mars`
- ```
Attachments
If you want to set default attachments sent with every email:
- ``` js
- const Email = require('email-templates');
- const email = new Email({
- message: {
- from: 'test@example.com',
- attachments: [
- {
- filename: 'text1.txt',
- content: 'hello world!'
- }
- ]
- }
- });
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- name: 'Elon'
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
If you want to set attachments sent individually:
- ``` js
- const Email = require('email-templates');
- const email = new Email({
- message: {
- from: 'test@example.com'
- },
- transport: {
- jsonTransport: true
- }
- });
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com',
- attachments: [
- {
- filename: 'text1.txt',
- content: 'hello world!'
- }
- ]
- },
- locals: {
- name: 'Elon'
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
Automatic Inline CSS via Stylesheets
- ```pug
- link(rel="stylesheet", href="/css/app.css", data-inline)
- ```
- ``` js
- const email = new Email({
- //
- juice: true,
- // Override juice global settings
- juiceSettings: {
- tableElements: ['TABLE']
- },
- juiceResources: {
- preserveImportant: true,
- webResources: {
- //
- // this is the relative directory to your CSS/image assets
- // and its default path is `build/`:
- //
- // e.g. if you have the following in the ` of your template:
- // ``
- // then this assumes that the file `build/style.css` exists
- //
- relativeTo: path.resolve('build')
- //
- // but you might want to change it to something like:
- // relativeTo: path.join(__dirname, '..', 'assets')
- // (so that you can re-use CSS/images that are used in your web-app)
- //
- }
- }
- });
- ```
Render HTML and/or Text
If you need to render a specific email template file (e.g. the HTML version):
- ``` js
- const Email = require('email-templates');
- const email = new Email();
- .render('mars/html', {
- name: 'Elon'
- })
- .then(console.log)
- .catch(console.error);
- ```
- ```sh
- .
- ├── app.js
- └── emails
- └── mars
- ├── html.pug
- ├── text.pug
- └── subject.pug
- ```
If you need pass juiceResources in render function, with this option you don't need create Email instance every time
- ``` js
- const Email = require('email-templates');
- const email = new Email();
- .render({
- path: 'mars/html',
- juiceResources: {
- preserveImportant: true,
- webResources: {
- // view folder path, it will get css from `mars/style.css`
- relativeTo: path.resolve('mars')
- }
- }
- }, {
- name: 'Elon'
- })
- .then(console.log)
- .catch(console.error);
- ```
- ```sh
- .
- ├── app.js
- └── emails
- └── mars
- ├── html.pug
- ├── text.pug
- ├── subject.pug
- └── style.css
- ```
If you need to render all available template files for a given email template (e.g. html.pug, text.pug, and subject.pug – you can use email.renderAll (this is the method that email.send uses).
- ``` js
- const Email = require('email-templates');
- const email = new Email();
- .renderAll('mars', {
- name: 'Elon'
- })
- .then(console.log)
- .catch(console.error);
- ```
If you need to render multiple, specific templates at once (but not all email templates available), then you can use Promise.all in combination with email.render:
- ``` js
- const Email = require('email-templates');
- const email = new Email();
- const locals = { name: 'Elon' };
- Promise
- .all([
- email.render('mars/html', locals),
- email.render('mars/text', locals)
- ])
- .then(([ html, text ]) => {
- console.log('html', html);
- console.log('text', text);
- })
- .catch(console.error);
- ```
Cache Pug Templates
Localization
Don't want to handle localization and translation yourself? Just use [Lad][lad] – it's built in and uses [mandarin][] (with automatic Google Translate support) under the hood!
- ``` js
- const Email = require('email-templates');
- const email = new Email({
- message: {
- from: 'test@example.com'
- },
- transport: {
- jsonTransport: true
- },
- i18n: {} // <------ HERE
- });
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- locale: 'en', // <------ CUSTOMIZE LOCALE HERE (defaults to `i18n.defaultLocale` - `en`)
- // is your user french?
- // locale: 'fr',
- name: 'Elon'
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
html.pug:
- ```pug
- p= `${t('Hi')} ${name},`
- p= t('Welcome to Mars, the red planet.')
- ```
subject.pug:
- ```pug
- p= `${t('Hi')} ${name}, ${t('welcome to Mars')}`
- ```
- ```pug
- p: :translate(locale) Welcome to Mars, the red planet.
- ```
Localization using Handlebars template engine
- ``` json
- {
- "greetings": "Hi {{ firstname }}",
- "welcome_message": "Welcome to Mars, the red planet."
- }
- ```
html.hbs:
- ```handlebars
- <p>{{ t "greetings" firstname="Marcus" }}</p>
- <p>{{ t "welcome_message" }}</p>
- ```
- ``` js
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- locale: 'en', // <------ CUSTOMIZE LOCALE HERE (defaults to `i18n.defaultLocale` - `en`)
- // is your user french?
- // locale: 'fr',
- name: 'Elon',
- $t(key, options) {
- // <------ THIS IS OUR OWN TRANSLATION HELPER
- return options.data.root.t(
- { phrase: key, locale: options.data.root.locale },
- options.hash
- );
- }
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
html.hbs:
- ```handlebars
- <p>{{ $t "greetings" firstname="Marcus" }}</p>
- <p>{{ $t "welcome_message" }}</p>
- ```
Text-Only Email (no HTML)
- ``` js
- const Email = require('email-templates');
- const email = new Email({
- message: {
- from: 'test@example.com'
- },
- transport: {
- jsonTransport: true
- },
- textOnly: true // <----- HERE
- });
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- name: 'Elon'
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
Prefix Subject Lines
- ``` js
- const Email = require('email-templates');
- const env = process.env.NODE_ENV || 'development';
- const email = new Email({
- message: {
- from: 'test@example.com'
- },
- transport: {
- jsonTransport: true
- },
- subjectPrefix: env === 'production' ? false : `[${env.toUpperCase()}] `; // <--- HERE
- });
- ```
Custom Text Template
By default we use html-to-text to generate a plaintext version and attach it as message.text.
- ``` js
- const Email = require('email-templates');
- const email = new Email({
- message: {
- from: 'test@example.com'
- },
- transport: {
- jsonTransport: true
- },
- htmlToText: false // <----- HERE
- });
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- name: 'Elon'
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
text.pug:
- ```pug
- | Hi #{name},
- | Welcome to Mars, the red planet.
- ```
Custom Template Engine (e.g. EJS)
- ```sh
- npm install ejs
- ```
- ``` js
- const Email = require('email-templates');
- const email = new Email({
- message: {
- from: 'test@example.com'
- },
- transport: {
- jsonTransport: true
- },
- views: {
- options: {
- extension: 'ejs' // <---- HERE
- }
- }
- });
- ```
Custom Default Message Options
Here's an example showing how to set a default custom header and a list unsubscribe header:
- ``` js
- const Email = require('email-templates');
- const email = new Email({
- message: {
- from: 'test@example.com',
- headers: {
- 'X-Some-Custom-Thing': 'Some-Value'
- },
- list: {
- unsubscribe: 'https://example.com/unsubscribe'
- }
- },
- transport: {
- jsonTransport: true
- }
- });
- ```
Custom Rendering (e.g. from a MongoDB database)
- ``` js
- const ejs = require('ejs');
- const email = new Email({
- // ...
- render: (view, locals) => {
- return new Promise((resolve, reject) => {
- // this example assumes that `template` returned
- // is an ejs-based template string
- // view = `${template}/html` or `${template}/subject` or `${template}/text`
- db.templates.findOne({ name: view }, (err, template) => {
- if (err) return reject(err);
- if (!template) return reject(new Error('Template not found'));
- let html = ejs.render(template, locals);
- html = await email.juiceResources(html);
- resolve(html);
- });
- });
- }
- });
- ```
Absolute Path to Templates
Relative example:
- ``` js
- .send({
- template: 'mars',
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- name: 'Elon'
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
Absolute example:
- ``` js
- const path = require('path');
- // ...
- .send({
- template: path.join(__dirname, 'some', 'folder', 'mars')
- message: {
- to: 'elon@spacex.com'
- },
- locals: {
- name: 'Elon'
- }
- })
- .then(console.log)
- .catch(console.error);
- ```
Open Email Previews in Firefox
Firefox example:
- ``` js
- const email = new Email({
- // ...
- preview: {
- open: {
- app: 'firefox',
- wait: false
- }
- }
- });
- ```
Options
Plugins
- ``` js
- const email = new Email({
- // ...
- juiceResources: {
- preserveImportant: true,
- webResources: {
- relativeTo: path.resolve('build'),
- images: true // <--- set this as `true`
- }
- }
- });
- ```
Breaking Changes
v10.0.0
v9.0.0
v8.0.0
- ```diff
- +Hi,
- +
- +email-templates rocks!
- +
- +Cheers,
- +The team
- -Hi,email-templates rocks!
- -Cheers,The team
- ```
v7.0.0
` block). A major version bump was done due to the significant visual change in the preview rendering of emails.
v6.0.0
Performance should be significantly improved as the rendering of subject, html, and text parts now occurs asynchronously in parallel (previously it was in series and had blocking lookup calls).We removed [bluebird][] and replaced it with a lightweight alternative [pify][] (since all we were using was the Promise.promisify method from bluebird as well).This package now only supports Node v8.x+ (due to [preview-email][]'s [open][] dependency requiring it).Configuration for the preview option has slightly changed, which now allows you to specify a custom template and stylesheets for preview rendering.
> If you were using a custom preview option before, you will need to change it slightly:
- ```diff
- const email = new Email({
- // ...
- preview: {
- + open: {
- + app: 'firefox',
- + wait: false
- + }
- - app: 'firefox',
- - wait: false
- }
- });
- ```
v5.0.0
In version 4.x+, we changed the order of defaults being set. See #313 for more information. This allows you to override message options such asfrom (even if you have a global default from set).
v4.0.0
See v5.0.0 above
v3.0.0
If you are upgrading from v2 or prior to v3, please note that the following breaking API changes occurred:
1. You need to have Node v6.4.0+, we recommend using nvm to manage your Node versions.
2. Instead of calling const newsletter = new EmailTemplate(...args), you now call const email = new Email(options).
The arguments you pass to the constructor have changed as well. Previously you'd pass new EmailTemplate(templateDir, options). Now you will need to pass simply one object with a configuration as an argument to the constructor. If your templateDir path is the "emails" folder in the root of your project (basically ./emails folder) then you do not need to pass it at all since it is the default per the configuration object. The previous value for templateDir can be used as such:
- ```diff
- -const newsletter = new EmailTemplate(templateDir);
- +const email = new Email({
- + views: { root: templateDir }
- +});
- ```
Note that if you are inlining CSS, you should also make sure that the option for juiceResources.webResources.relativeTo is accurate.
3. Instead of calling newsletter.render(locals, callback) you now call email.render(template, locals). The return value of email.render when invoked is a Promise and does not accept a callback function.
> NOTE: email-templates v3 now has an email.send method (see basic usage example) which usesnodemailer; you should now use email.send instead of email.render!
- ```diff
- -newsletter.render({}, (err, result) => {
- - if (err) return console.error(err);
- - console.log(result);
- -});
- +email.render(template, {}).then(console.log).catch(console.error);
- ```
4. Localized template directories are no longer supported. We now support i18n translations out of the box. See Localization for more info.
5. A new method email.send has been added. This allows you to create a Nodemailer transport and send an email template all at once (it calls email.render internally). See the Basic usage documentation above for an example.
6. There are new options options.send and options.preview. Both are Boolean values and configured automatically based off the environment. Take a look at the configuration object. Note that you can optionally pass an Object topreview option, which gets passed along to [open's options][open-options].
7. If you wish to send emails in development or test environment (disabled by default), set options.send to true.
Tip
Instead of having to configure this for yourself, you could just use [Lad][] instead.
Related
[lad][] - Scaffold a [Koa][] webapp and API framework for [Node.js][node][lass][] - Scaffold a modern boilerplate for [Node.js][node][cabin][] - Logging and analytics solution for [Node.js][node], [Lad][], [Koa][], and [Express][][forward-email][] - Free, encrypted, and open-source email forwarding service for custom domains
Contributors
Name Website -------------- ------------------------- **Nick
License
##
[node]: https://nodejs.org
[npm]: https://www.npmjs.com/
[pug]: https://pugjs.org
[supported-engines]: https://github.com/tj/consolidate.js/#supported-template-engines
[nodemailer]: https://nodemailer.com/plugins/
[font-awesome-assets]: https://github.com/ladjs/font-awesome-assets
[custom-fonts-in-emails]: https://github.com/ladjs/custom-fonts-in-emails
[nodemailer-base64-to-s3]: https://github.com/ladjs/nodemailer-base64-to-s3
[lad]: https://lad.js.org
[i18n]: https://github.com/ladjs/i18n#options
[fa]: http://fontawesome.io/
[nodemailer-transport]: https://nodemailer.com/transports/
[postmark]: https://postmarkapp.com/
[ejs]: http://ejs.co/
[cache-pug-templates]: https://github.com/ladjs/cache-pug-templates
[preview-email]: https://github.com/forwardemail/preview-email
[attachments]: https://nodemailer.com/message/attachments/
[lass]: https://lass.js.org
[cabin]: https://cabinjs.com
[forward-email]: https://forwardemail.net
[koa]: https://koajs.com/
[express]: https://expressjs.com
[open-options]: https://github.com/sindresorhus/open#options
[mandarin]: https://github.com/ladjs/mandarin
[consolidate]: https://github.com/tj/consolidate.js
[nodemailer-message-object]: https://nodemailer.com/message/
[html-to-text]: https://github.com/werk85/node-html-to-text
[web-resource-inliner]: https://github.com/jrit/web-resource-inliner
[nodemailer-transports]: https://nodemailer.com/transports/
[juice]: https://github.com/Automattic/juice
[bluebird]: https://github.com/petkaantonov/bluebird
[pify]: https://github.com/sindresorhus/pify
[open]: https://github.com/sindresorhus/open