UNPKG

32.4 kBMarkdownView Raw
1# [**Email Templates**](https://github.com/forwardemail/email-templates)
2
3[![build status](https://travis-ci.com/forwardemail/email-templates.svg)](https://travis-ci.com/forwardemail/email-templates)
4[![code coverage](https://img.shields.io/codecov/c/github/forwardemail/email-templates.svg)](https://codecov.io/gh/forwardemail/email-templates)
5[![code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)
6[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
7[![made with lass](https://img.shields.io/badge/made_with-lass-95CC28.svg)](https://lass.js.org)
8[![license](https://img.shields.io/github/license/forwardemail/email-templates.svg)](LICENSE)
9
10> :heart: Love this project? Support <a href="https://github.com/niftylettuce" target="_blank">@niftylettuce's</a> [FOSS](https://en.wikipedia.org/wiki/Free_and_open-source_software) on <a href="https://patreon.com/niftylettuce" target="_blank">Patreon</a> or <a href="https://paypal.me/niftylettuce">PayPal</a> :unicorn:
11
12Create, [preview][preview-email], and send custom email templates for [Node.js][node]. Highly configurable and supports automatic inline CSS, stylesheets, embedded images and fonts, and much more! Made for sending beautiful emails with [Lad][].
13
14
15## Table of Contents
16
17* [Install](#install)
18* [Preview](#preview)
19* [Usage](#usage)
20 * [Debugging](#debugging)
21 * [Basic](#basic)
22 * [Attachments](#attachments)
23 * [Automatic Inline CSS via Stylesheets](#automatic-inline-css-via-stylesheets)
24 * [Render HTML and/or Text](#render-html-andor-text)
25 * [Cache Pug Templates](#cache-pug-templates)
26 * [Localization](#localization)
27 * [Text-Only Email (no HTML)](#text-only-email-no-html)
28 * [Prefix Subject Lines](#prefix-subject-lines)
29 * [Custom Text Template](#custom-text-template)
30 * [Custom Template Engine (e.g. EJS)](#custom-template-engine-eg-ejs)
31 * [Custom Default Message Options](#custom-default-message-options)
32 * [Custom Rendering (e.g. from a MongoDB database)](#custom-rendering-eg-from-a-mongodb-database)
33 * [Absolute Path to Templates](#absolute-path-to-templates)
34 * [Open Email Previews in Firefox](#open-email-previews-in-firefox)
35* [Options](#options)
36* [Plugins](#plugins)
37* [Breaking Changes](#breaking-changes)
38 * [v8.0.0](#v800)
39 * [v7.0.0](#v700)
40 * [v6.0.0](#v600)
41 * [v5.0.0](#v500)
42 * [v4.0.0](#v400)
43 * [v3.0.0](#v300)
44* [Tip](#tip)
45* [Related](#related)
46* [Contributors](#contributors)
47* [License](#license)
48
49
50## Install
51
52> By default we recommend [pug][] for your template engine, but you can use [any template engine][supported-engines].
53
54[npm][]:
55
56```sh
57npm install email-templates pug
58```
59
60[yarn][]:
61
62```sh
63yarn add email-templates pug
64```
65
66
67## Preview
68
69We've added [preview-email][] by default to this package!
70
71This means that (by default) in the development environment (e.g. `NODE_ENV=development`) your emails will be rendered to the tmp directory for you and automatically opened in the browser.
72
73If you have trouble previewing emails in your browser, you can configure a `preview` option which gets passed along to [open's options][open-options] (e.g. `preview: { open: { app: 'firefox' } }`).
74
75See the example below for [Open Email Previews in Firefox](#open-email-previews-in-firefox).
76
77
78## Usage
79
80### Debugging
81
82#### Environment Flag
83
84If you run into any issues with configuration, files, templates, locals, etc, then you can use the `DEBUG` environment flag:
85
86```sh
87DEBUG=email-templates node app.js
88```
89
90This will output to the console all debug statements in our codebase for this package.
91
92#### Inspect Message
93
94As of v3.6.1 you can now inspect the message passed to `nodemailer.sendMail` internally.
95
96In the response object from `email.send`, you have access to `res.originalMessage`:
97
98```js
99email
100 .send({
101 template: 'mars',
102 message: {
103 to: 'elon@spacex.com'
104 },
105 locals: {
106 name: 'Elon'
107 }
108 })
109 .then(res => {
110 console.log('res.originalMessage', res.originalMessage)
111 })
112 .catch(console.error);
113```
114
115### Basic
116
117> 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][]).
118>
119> If you want to send emails in `development` or `test` environments, set `options.send` to `true`.
120
121```js
122const Email = require('email-templates');
123
124const email = new Email({
125 message: {
126 from: 'niftylettuce@gmail.com'
127 },
128 // uncomment below to send emails in development/test env:
129 // send: true
130 transport: {
131 jsonTransport: true
132 }
133});
134
135email
136 .send({
137 template: 'mars',
138 message: {
139 to: 'elon@spacex.com'
140 },
141 locals: {
142 name: 'Elon'
143 }
144 })
145 .then(console.log)
146 .catch(console.error);
147```
148
149The example above assumes you have the following directory structure:
150
151```sh
152.
153├── app.js
154└── emails
155 └── mars
156 ├── html.pug
157 └── subject.pug
158```
159
160And the contents of the `pug` files are:
161
162> `html.pug`:
163
164```pug
165p Hi #{name},
166p Welcome to Mars, the red planet.
167```
168
169> `subject.pug`:
170
171```pug
172= `Hi ${name}, welcome to Mars`
173```
174
175### Attachments
176
177Please reference [Nodemailer's attachment documentation][attachments] for further reference.
178
179> If you want to set default attachments sent with every email:
180
181```js
182const Email = require('email-templates');
183
184const email = new Email({
185 message: {
186 from: 'niftylettuce@gmail.com',
187 attachments: [
188 {
189 filename: 'text1.txt',
190 content: 'hello world!'
191 }
192 ]
193 }
194});
195
196email
197 .send({
198 template: 'mars',
199 message: {
200 to: 'elon@spacex.com'
201 },
202 locals: {
203 name: 'Elon'
204 }
205 })
206 .then(console.log)
207 .catch(console.error);
208```
209
210> If you want to set attachments sent individually:
211
212```js
213const Email = require('email-templates');
214
215const email = new Email({
216 message: {
217 from: 'niftylettuce@gmail.com'
218 },
219 transport: {
220 jsonTransport: true
221 }
222});
223
224email
225 .send({
226 template: 'mars',
227 message: {
228 to: 'elon@spacex.com',
229 attachments: [
230 {
231 filename: 'text1.txt',
232 content: 'hello world!'
233 }
234 ]
235 },
236 locals: {
237 name: 'Elon'
238 }
239 })
240 .then(console.log)
241 .catch(console.error);
242```
243
244### Automatic Inline CSS via Stylesheets
245
246Simply include the path or URL to the stylesheet in your template's `<head>`:
247
248```pug
249link(rel="stylesheet", href="/css/app.css", data-inline)
250```
251
252This will look for the file `/css/app.css` in the `build/` folder.
253
254If this asset is in another folder, then you will need to modify the default options when creating an `Email` instance:
255
256```js
257const email = new Email({
258 // <https://github.com/Automattic/juice>
259 juice: true,
260 // Override juice global settings <https://github.com/Automattic/juice#juicecodeblocks>
261 juiceSettings: {
262 tableElements: ['TABLE']
263 },
264 juiceResources: {
265 preserveImportant: true,
266 webResources: {
267 //
268 // this is the relative directory to your CSS/image assets
269 // and its default path is `build/`:
270 //
271 // e.g. if you have the following in the `<head`> of your template:
272 // `<link rel="stylesheet" href="style.css" data-inline="data-inline">`
273 // then this assumes that the file `build/style.css` exists
274 //
275 relativeTo: path.resolve('build')
276 //
277 // but you might want to change it to something like:
278 // relativeTo: path.join(__dirname, '..', 'assets')
279 // (so that you can re-use CSS/images that are used in your web-app)
280 //
281 }
282 }
283});
284```
285
286### Render HTML and/or Text
287
288If you don't need this module to send your email, you can still use it to render HTML and/or text templates.
289
290Simply use the `email.render(view, locals)` method we expose (it's the same method that `email.send` uses internally).
291
292> If you need to render a specific email template file (e.g. the HTML version):
293
294```js
295const Email = require('email-templates');
296
297const email = new Email();
298
299email
300 .render('mars/html', {
301 name: 'Elon'
302 })
303 .then(console.log)
304 .catch(console.error);
305```
306
307The example above assumes you have the following directory structure (note that this example would only render the `html.pug` file):
308
309```sh
310.
311├── app.js
312└── emails
313 └── mars
314 ├── html.pug
315 ├── text.pug
316 └── subject.pug
317```
318
319The Promise for `email.render` resolves with a String (the HTML or text rendered).
320
321> If you need pass juiceResources in render function, with this option you don't need create Email instance every time
322
323```js
324const Email = require('email-templates');
325
326const email = new Email();
327
328email
329 .render({
330 path: 'mars/html',
331 juiceResources: {
332 preserveImportant: true,
333 webResources: {
334 // view folder path, it will get css from `mars/style.css`
335 relativeTo: path.resolve('mars')
336 }
337 }
338 }, {
339 name: 'Elon'
340 })
341 .then(console.log)
342 .catch(console.error);
343```
344
345The example above will be useful when you have a structure like this, this will be useful when you have a separate CSS file for every template
346
347```sh
348.
349├── app.js
350└── emails
351 └── mars
352 ├── html.pug
353 ├── text.pug
354 ├── subject.pug
355 └── style.css
356```
357
358The Promise for `email.render` resolves with a String (the HTML or text rendered).
359
360> 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).
361
362```js
363const Email = require('email-templates');
364
365const email = new Email();
366
367email
368 .renderAll('mars', {
369 name: 'Elon'
370 })
371 .then(console.log)
372 .catch(console.error);
373```
374
375> 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`:
376
377```js
378const Email = require('email-templates');
379
380const email = new Email();
381const locals = { name: 'Elon' };
382
383Promise
384 .all([
385 email.render('mars/html', locals),
386 email.render('mars/text', locals)
387 ])
388 .then(([ html, text ]) => {
389 console.log('html', html);
390 console.log('text', text);
391 })
392 .catch(console.error);
393```
394
395### Cache Pug Templates
396
397Out of the box, templates are cached as they are compiled (e.g. as emails are sent, the template they're using is cached). However these templates are not cached in-advance, so the first emails sent of each template will be slower to send.
398
399We strongly suggest to pre-cache your templates with [cache-pug-templates][] (if you're using the default [Pug][] template engine).
400
401If you do not do this, then your Pug templates will re-compile and re-cache every time you deploy new code and restart your app.
402
403Note that you will need to specify the `views` option to your `new CachePugTemplates({ views: '...' });` instance, with `views` being a file path (Array or String) to your email template directory. See [cache-pug-templates][] documentation for more information.
404
405### Localization
406
407All you need to do is simply pass an [i18n][] configuration object as `config.i18n` (or an empty one as this example shows to use defaults).
408
409> 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!
410
411```js
412const Email = require('email-templates');
413
414const email = new Email({
415 message: {
416 from: 'niftylettuce@gmail.com'
417 },
418 transport: {
419 jsonTransport: true
420 },
421 i18n: {} // <------ HERE
422});
423
424email
425 .send({
426 template: 'mars',
427 message: {
428 to: 'elon@spacex.com'
429 },
430 locals: {
431 locale: 'en', // <------ CUSTOMIZE LOCALE HERE (defaults to `i18n.defaultLocale` - `en`)
432 // is your user french?
433 // locale: 'fr',
434 name: 'Elon'
435 }
436 })
437 .then(console.log)
438 .catch(console.error);
439```
440
441Then slightly modify your templates to use localization functions.
442
443> `html.pug`:
444
445```pug
446p= `${t('Hi')} ${name},`
447p= t('Welcome to Mars, the red planet.')
448```
449
450> `subject.pug`:
451
452```pug
453p= `${t('Hi')} ${name}, ${t('welcome to Mars')}`
454```
455
456Note that if you use [Lad][], you have a built-in filter called `translate`:
457
458```pug
459p: :translate(locale) Welcome to Mars, the red planet.
460```
461
462#### Localization using Handlebars template engine
463
464If you are using handlebars and you are using localization files with named values, you will quickly see that
465there is no way to properly call the `t` function in your template and specify named values.
466
467If, for example you have this in your translation file:
468
469```json
470{
471 "greetings": "Hi {{ firstname }}",
472 "welcome_message": "Welcome to Mars, the red planet."
473}
474```
475
476And you would like to use it in your template like this:
477
478> `html.hbs`:
479
480```handlebars
481<p>{{ t "greetings" firstname="Marcus" }}</p>
482<p>{{ t "welcome_message" }}</p>
483```
484
485This would not work because the second argument sent by handlebars to the function would be a handlebar helper
486options object instead of just the named values.
487
488A possible workaround you can use is to introduce your own translation helper in your template locals:
489
490```js
491email
492 .send({
493 template: 'mars',
494 message: {
495 to: 'elon@spacex.com'
496 },
497 locals: {
498 locale: 'en', // <------ CUSTOMIZE LOCALE HERE (defaults to `i18n.defaultLocale` - `en`)
499 // is your user french?
500 // locale: 'fr',
501 name: 'Elon',
502 $t(key, options) {
503 // <------ THIS IS OUR OWN TRANSLATION HELPER
504 return options.data.root.t(
505 { phrase: key, locale: options.data.root.locale },
506 options.hash
507 );
508 }
509 }
510 })
511 .then(console.log)
512 .catch(console.error);
513```
514
515Then slightly modify your templates to use your own translation helper functions.
516
517> `html.hbs`:
518
519```handlebars
520<p>{{ $t "greetings" firstname="Marcus" }}</p>
521<p>{{ $t "welcome_message" }}</p>
522```
523
524### Text-Only Email (no HTML)
525
526If you wish to have only a text-based version of your email you can simply pass the option `textOnly: true`.
527
528Regardless if you use the `htmlToText` option or not (see next example), it will still render only a text-based version.
529
530```js
531const Email = require('email-templates');
532
533const email = new Email({
534 message: {
535 from: 'niftylettuce@gmail.com'
536 },
537 transport: {
538 jsonTransport: true
539 },
540 textOnly: true // <----- HERE
541});
542
543email
544 .send({
545 template: 'mars',
546 message: {
547 to: 'elon@spacex.com'
548 },
549 locals: {
550 name: 'Elon'
551 }
552 })
553 .then(console.log)
554 .catch(console.error);
555```
556
557### Prefix Subject Lines
558
559You can pass an option to prefix subject lines with a string, which is super useful for deciphering development / staging / production environment emails.
560
561For example, you could make it so on non-production environments the email is prefixed with a `[DEVELOPMENT] Some Subject Line Here`.
562
563You could do this manually by passing a `message.subject` property, however if you are storing your subject lines in templates (e.g. `subject.ejs` or `subject.pug`) then it's not as easy.
564
565Simply use the `subjectPrefix` option and set it to whatever you wish (**note you will need to append a trailing space if you wish to have a space after the prefix; see example below**):
566
567```js
568const Email = require('email-templates');
569
570const env = process.env.NODE_ENV || 'development';
571
572const email = new Email({
573 message: {
574 from: 'niftylettuce@gmail.com'
575 },
576 transport: {
577 jsonTransport: true
578 },
579 subjectPrefix: env === 'production' ? false : `[${env.toUpperCase()}] `; // <--- HERE
580});
581```
582
583### Custom Text Template
584
585> By default we use `html-to-text` to generate a plaintext version and attach it as `message.text`.
586
587If you'd like to customize the text body, you can pass `message.text` or create a `text` template file just like you normally would for `html` and `subject`.
588
589You may also set `config.htmlToText: false` to force the usage of the `text` template file.
590
591```js
592const Email = require('email-templates');
593
594const email = new Email({
595 message: {
596 from: 'niftylettuce@gmail.com'
597 },
598 transport: {
599 jsonTransport: true
600 },
601 htmlToText: false // <----- HERE
602});
603
604email
605 .send({
606 template: 'mars',
607 message: {
608 to: 'elon@spacex.com'
609 },
610 locals: {
611 name: 'Elon'
612 }
613 })
614 .then(console.log)
615 .catch(console.error);
616```
617
618> `text.pug`:
619
620```pug
621| Hi #{name},
622| Welcome to Mars, the red planet.
623```
624
625### Custom Template Engine (e.g. EJS)
626
6271. Install your desired template engine (e.g. [EJS][])
628
629 [npm][]:
630
631 ```sh
632 npm install ejs
633 ```
634
635 [yarn][]:
636
637 ```sh
638 yarn add ejs
639 ```
640
6412. Set the extension in options and send an email
642
643 ```js
644 const Email = require('email-templates');
645
646 const email = new Email({
647 message: {
648 from: 'niftylettuce@gmail.com'
649 },
650 transport: {
651 jsonTransport: true
652 },
653 views: {
654 options: {
655 extension: 'ejs' // <---- HERE
656 }
657 }
658 });
659 ```
660
661### Custom Default Message Options
662
663You can configure your Email instance to have default message options, such as a default "From", an unsubscribe header, etc.
664
665For a list of all available message options and fields see [the Nodemailer message reference](https://nodemailer.com/message/).
666
667> Here's an example showing how to set a default custom header and a list unsubscribe header:
668
669```js
670const Email = require('email-templates');
671
672const email = new Email({
673 message: {
674 from: 'niftylettuce@gmail.com',
675 headers: {
676 'X-Some-Custom-Thing': 'Some-Value'
677 },
678 list: {
679 unsubscribe: 'https://niftylettuce.com/unsubscribe'
680 }
681 },
682 transport: {
683 jsonTransport: true
684 }
685});
686```
687
688### Custom Rendering (e.g. from a MongoDB database)
689
690You can pass a custom `config.render` function which accepts two arguments `view` and `locals` and must return a `Promise`.
691
692Note that if you specify a custom `config.render`, you should have it use `email.juiceResources` before returning the final HTML. The example below shows how to do this.
693
694If you wanted to read a stored EJS template from MongoDB, you could do something like:
695
696```js
697const ejs = require('ejs');
698
699const email = new Email({
700 // ...
701 render: (view, locals) => {
702 return new Promise((resolve, reject) => {
703 // this example assumes that `template` returned
704 // is an ejs-based template string
705 // view = `${template}/html` or `${template}/subject` or `${template}/text`
706 db.templates.findOne({ name: view }, (err, template) => {
707 if (err) return reject(err);
708 if (!template) return reject(new Error('Template not found'));
709 let html = ejs.render(template, locals);
710 html = await email.juiceResources(html);
711 resolve(html);
712 });
713 });
714 }
715});
716```
717
718### Absolute Path to Templates
719
720As of v5.0.1+ we now support passing absolute paths to templates for rendering (per discussion in [#320](https://github.com/forwardemail/email-templates/issues/320).
721
722For both `email.send` and `email.render`, the `template` option passed can be a relative path or absolute:
723
724> Relative example:
725
726```js
727email
728 .send({
729 template: 'mars',
730 message: {
731 to: 'elon@spacex.com'
732 },
733 locals: {
734 name: 'Elon'
735 }
736 })
737 .then(console.log)
738 .catch(console.error);
739```
740
741> Absolute example:
742
743```js
744const path = require('path');
745
746// ...
747
748email
749 .send({
750 template: path.join(__dirname, 'some', 'folder', 'mars')
751 message: {
752 to: 'elon@spacex.com'
753 },
754 locals: {
755 name: 'Elon'
756 }
757 })
758 .then(console.log)
759 .catch(console.error);
760```
761
762### Open Email Previews in Firefox
763
764The `preview` option can be a custom Object of options to pass along to [open's options][open-options].
765
766> Firefox example:
767
768```js
769const email = new Email({
770 // ...
771 preview: {
772 open: {
773 app: 'firefox',
774 wait: false
775 }
776 }
777});
778```
779
780
781## Options
782
783For a list of all available options and defaults [view the configuration object](src/index.js), or reference the list below:
784
785* `views` (Object)
786 * `root` (String) - defaults to the current working directory's "emails" folder via `path.resolve('emails')`
787 * `options` (Object)
788 * `extension` (String) - defaults to `'pug'`, and is the default file extension for templates
789 * `map` (Object) - a template file extension mapping, defaults to `{ hbs: 'handlebars', njk: 'nunjucks' }` (this is useful if you use different file extension naming conventions)
790 * `engineSource` (Object) - the default template engine source, defaults to [consolidate][]
791 * `locals` (Object) - locals to pass to templates for rendering
792 * `cache` (Boolean) - defaults to `false` for `development` and `test` environments, and `true` for all others (via `process.env.NODE_ENV`), whether or not to cache templates
793 * `pretty` (Boolean) - defaults to `true`, but is automatically set to `false` for subject templates and text-based emails
794* `message` (Object) - default [Nodemailer message object][nodemailer-message-object] for messages to inherit (defaults to an empty object `{}`)
795* `send` (Boolean) - whether or not to send emails, defaults to `false` for `development` and `test` environments, and `true` for all others (via `process.env.NODE_ENV`) (**NOTE: IF YOU ARE NOT USING `NODE_ENV` YOU WILL NEED TO MANUALLY SET THIS TO `true`**)
796* `preview` (Boolean or Object) - whether or not to preview emails using [preview-email][], defaults to `false` unless the environment is `development` (via `process.env.NODE_ENV`)
797* `i18n` (Boolean or Object) - translation support for email templates, this accepts an I18N configuration object (defaults to `false`, which means it is disabled) which is passed along to [@ladjs/i18n][i18n] – see [Localization](#localization) example for more insight
798* `render` (Function) - defaults to a stable function that accepts two argument, `view` (String) and `locals` (Object) - you should not need to set this unless you have a need for custom rendering (see [Custom Rendering (e.g. from a MongoDB database)](#custom-rendering-eg-from-a-mongodb-database))
799* `customRender` (Boolean) - defaults to `false`, unless you pass your own `render` function, and in that case it will be automatically set to `true`
800* `textOnly` (Boolean) - whether or not to force text-only rendering of a template and disregard the template folder (defaults to `false`)
801* `htmlToText` (Object) - configuration object for [html-to-text][]
802 * `ignoreImage` (Boolean) - defaults to `true`
803* `subjectPrefix` (Boolean or String) - defaults to `false`, but if set to a string it will use that string as a prefix for your emails' subjects
804* `juice` (Boolean) - whether or not to use [juice][] when rendering templates (defaults to `true`) (note that if you have a custom rendering function you will need to implement [juice][] in it yourself)
805* `juiceResources` (Object) - options to pass to `juice.juiceResources` method (only used if `juice` option is set to `true`, see [juice's][juice] API for more information
806 * `preserveImportant` (Boolean) - defaults to `true`
807 * `webResources` (Object) - an options object that will be passed to [web-resource-inliner][]
808 * `relativeTo` (String) - defaults to the current working directory's "build" folder via `path.resolve('build')` (**NOTE: YOU SHOULD MODIFY THIS PATH TO WHERE YOUR BUILD/ASSETS FOLDER IS**)
809 * `images` (Boolean or Number) - defaults to `false`, and is whether or not to inline images unless they have an exclusion attribute (see [web-resource-inliner][] for more insight), if it is set to a Number then that is used as the KB threshold
810* `transport` (Object) - a transport configuration object or a Nodemailer transport instance created via `nodemailer.createTransport`, defaults to an empty object `{}`, see [Nodemailer transports][nodemailer-transports] documentation for more insight
811* `getPath` (Function) - a function that returns the path to a template file, defaults to `function (type, template) { return path.join(template, type); }`, and accepts three arguments `type`, `template`, and `locals`
812
813
814## Plugins
815
816You can use any [nodemailer][] plugin. Simply pass an existing transport instance as `config.transport`.
817
818You should add the [nodemailer-base64-to-s3][] plugin to convert base64 inline images to actual images stored on Amazon S3 and Cloudfront.
819
820When doing so (as of v4.0.2+), you will need to adjust your `email-templates` configuration to pass `images: true` as such:
821
822```js
823const email = new Email({
824 // ...
825 juiceResources: {
826 preserveImportant: true,
827 webResources: {
828 relativeTo: path.resolve('build'),
829 images: true // <--- set this as `true`
830 }
831 }
832});
833```
834
835We also highly recommend to add to your default `config.locals` the following:
836
837* [custom-fonts-in-emails][] - render any font in emails as an image w/retina support (no more Photoshop or Sketch exports!)
838* [font-awesome-assets][] - render any [Font Awesome][fa] icon as an image in an email w/retina support (no more Photoshop or Sketch exports!)
839
840
841## Breaking Changes
842
843See the [Releases](https://github.com/forwardemail/email-templates/releases) page for an up to date changelog.
844
845### v8.0.0
846
847We upgraded [html-to-text](https://github.com/html-to-text/node-html-to-text) to v6. As a result, automatically generated text versions of your emails will look slightly different, as per the example below:
848
849```diff
850+Hi,
851+
852+email-templates rocks!
853+
854+Cheers,
855+The team
856-Hi,email-templates rocks!
857-Cheers,The team
858```
859
860### v7.0.0
861
862We upgraded `preview-email` to `v2.0.0`, which supports stream attachments, and additionally the view rendering is slightly different (we simply iterate over header lines and format them in a `<pre><code>` block). A major version bump was done due to the significant visual change in the preview rendering of emails.
863
864### v6.0.0
865
866* 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).
867* 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).
868* This package now only supports Node v8.x+ (due to [preview-email][]'s [open][] dependency requiring it).
869* Configuration for the `preview` option has slightly changed, which now allows you to [specify a custom template and stylesheets](https://github.com/niftylettuce/preview-email#custom-preview-template-and-stylesheets) for preview rendering.
870
871 > If you were using a custom `preview` option before, you will need to change it slightly:
872
873 ```diff
874 const email = new Email({
875 // ...
876 preview: {
877 + open: {
878 + app: 'firefox',
879 + wait: false
880 + }
881 - app: 'firefox',
882 - wait: false
883 }
884 });
885 ```
886
887### v5.0.0
888
889In version 4.x+, we changed the order of defaults being set. See [#313](https://github.com/forwardemail/email-templates/issues/313) for more information. This allows you to override message options such as `from` (even if you have a global default `from` set).
890
891### v4.0.0
892
893See v5.0.0 above
894
895### v3.0.0
896
897> If you are upgrading from v2 or prior to v3, please note that the following breaking API changes occurred:
898
8991. You need to have Node v6.4.0+, we recommend using [nvm](https://github.com/creationix/nvm) to manage your Node versions.
900
9012. Instead of calling `const newsletter = new EmailTemplate(...args)`, you now call `const email = new Email(options)`.
902
903 * The arguments you pass to the constructor have changed as well.
904 * 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.
905 * 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](src/index.js).
906 * The previous value for `templateDir` can be used as such:
907
908 ```diff
909 -const newsletter = new EmailTemplate(templateDir);
910 +const email = new Email({
911 + views: { root: templateDir }
912 +});
913 ```
914
915 * Note that if you are inlining CSS, you should also make sure that the option for `juiceResources.webResources.relativeTo` is accurate.
916
9173. 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.
918
919 > **NOTE**: `email-templates` v3 now has an `email.send` method ([see basic usage example](#basic)) which uses `nodemailer`; you should now use `email.send` instead of `email.render`!
920
921 ```diff
922 -newsletter.render({}, (err, result) => {
923 - if (err) return console.error(err);
924 - console.log(result);
925 -});
926 +email.render(template, {}).then(console.log).catch(console.error);
927 ```
928
9294. Localized template directories are no longer supported. We now support i18n translations out of the box. See [Localization](#localization) for more info.
930
9315. 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](#basic) usage documentation above for an example.
932
9336. 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](src/index.js). Note that you can optionally pass an Object to `preview` option, which gets passed along to [open's options][open-options].
934
9357. If you wish to send emails in development or test environment (disabled by default), set `options.send` to `true`.
936
937
938## Tip
939
940Instead of having to configure this for yourself, you could just use [Lad][] instead.
941
942
943## Related
944
945* [lad][] - Scaffold a [Koa][] webapp and API framework for [Node.js][node]
946* [lass][] - Scaffold a modern boilerplate for [Node.js][node]
947* [cabin][] - Logging and analytics solution for [Node.js][node], [Lad][], [Koa][], and [Express][]
948* [forward-email][] - Free, encrypted, and open-source email forwarding service for custom domains
949* [lipo][] - Free image manipulation API service built on top of [Sharp][]
950
951
952## Contributors
953
954| Name | Website |
955| -------------- | ------------------------- |
956| **Nick Baugh** | <http://niftylettuce.com> |
957
958
959## License
960
961[MIT](LICENSE) © [Nick Baugh](http://niftylettuce.com)
962
963
964##
965
966[node]: https://nodejs.org
967
968[npm]: https://www.npmjs.com/
969
970[yarn]: https://yarnpkg.com/
971
972[pug]: https://pugjs.org
973
974[supported-engines]: https://github.com/tj/consolidate.js/#supported-template-engines
975
976[nodemailer]: https://nodemailer.com/plugins/
977
978[font-awesome-assets]: https://github.com/ladjs/font-awesome-assets
979
980[custom-fonts-in-emails]: https://github.com/ladjs/custom-fonts-in-emails
981
982[nodemailer-base64-to-s3]: https://github.com/ladjs/nodemailer-base64-to-s3
983
984[lad]: https://lad.js.org
985
986[i18n]: https://github.com/ladjs/i18n#options
987
988[fa]: http://fontawesome.io/
989
990[nodemailer-transport]: https://nodemailer.com/transports/
991
992[postmark]: https://postmarkapp.com/
993
994[ejs]: http://ejs.co/
995
996[cache-pug-templates]: https://github.com/ladjs/cache-pug-templates
997
998[preview-email]: https://github.com/niftylettuce/preview-email
999
1000[attachments]: https://nodemailer.com/message/attachments/
1001
1002[lass]: https://lass.js.org
1003
1004[cabin]: https://cabinjs.com
1005
1006[forward-email]: https://forwardemail.net
1007
1008[lipo]: https://lipo.io
1009
1010[koa]: https://koajs.com/
1011
1012[sharp]: http://sharp.dimens.io/
1013
1014[express]: https://expressjs.com
1015
1016[open-options]: https://github.com/sindresorhus/open#options
1017
1018[mandarin]: https://github.com/niftylettuce/mandarin
1019
1020[consolidate]: https://github.com/tj/consolidate.js
1021
1022[nodemailer-message-object]: https://nodemailer.com/message/
1023
1024[html-to-text]: https://github.com/werk85/node-html-to-text
1025
1026[web-resource-inliner]: https://github.com/jrit/web-resource-inliner
1027
1028[nodemailer-transports]: https://nodemailer.com/transports/
1029
1030[juice]: https://github.com/Automattic/juice
1031
1032[bluebird]: https://github.com/petkaantonov/bluebird
1033
1034[pify]: https://github.com/sindresorhus/pify
1035
1036[open]: https://github.com/sindresorhus/open
1037
\No newline at end of file