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 |
|
12 | Create, [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
|
57 | npm install email-templates pug
|
58 | ```
|
59 |
|
60 | [yarn][]:
|
61 |
|
62 | ```sh
|
63 | yarn add email-templates pug
|
64 | ```
|
65 |
|
66 |
|
67 | ## Preview
|
68 |
|
69 | We've added [preview-email][] by default to this package!
|
70 |
|
71 | This 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 |
|
73 | If 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 |
|
75 | See 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 |
|
84 | If you run into any issues with configuration, files, templates, locals, etc, then you can use the `DEBUG` environment flag:
|
85 |
|
86 | ```sh
|
87 | DEBUG=email-templates node app.js
|
88 | ```
|
89 |
|
90 | This will output to the console all debug statements in our codebase for this package.
|
91 |
|
92 | #### Inspect Message
|
93 |
|
94 | As of v3.6.1 you can now inspect the message passed to `nodemailer.sendMail` internally.
|
95 |
|
96 | In the response object from `email.send`, you have access to `res.originalMessage`:
|
97 |
|
98 | ```js
|
99 | email
|
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
|
122 | const Email = require('email-templates');
|
123 |
|
124 | const 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 |
|
135 | email
|
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 |
|
149 | The 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 |
|
160 | And the contents of the `pug` files are:
|
161 |
|
162 | > `html.pug`:
|
163 |
|
164 | ```pug
|
165 | p Hi #{name},
|
166 | p 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 |
|
177 | Please 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
|
182 | const Email = require('email-templates');
|
183 |
|
184 | const 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 |
|
196 | email
|
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
|
213 | const Email = require('email-templates');
|
214 |
|
215 | const email = new Email({
|
216 | message: {
|
217 | from: 'niftylettuce@gmail.com'
|
218 | },
|
219 | transport: {
|
220 | jsonTransport: true
|
221 | }
|
222 | });
|
223 |
|
224 | email
|
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 |
|
246 | Simply include the path or URL to the stylesheet in your template's `<head>`:
|
247 |
|
248 | ```pug
|
249 | link(rel="stylesheet", href="/css/app.css", data-inline)
|
250 | ```
|
251 |
|
252 | This will look for the file `/css/app.css` in the `build/` folder.
|
253 |
|
254 | If this asset is in another folder, then you will need to modify the default options when creating an `Email` instance:
|
255 |
|
256 | ```js
|
257 | const 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 |
|
288 | If you don't need this module to send your email, you can still use it to render HTML and/or text templates.
|
289 |
|
290 | Simply 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
|
295 | const Email = require('email-templates');
|
296 |
|
297 | const email = new Email();
|
298 |
|
299 | email
|
300 | .render('mars/html', {
|
301 | name: 'Elon'
|
302 | })
|
303 | .then(console.log)
|
304 | .catch(console.error);
|
305 | ```
|
306 |
|
307 | The 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 |
|
319 | The 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
|
324 | const Email = require('email-templates');
|
325 |
|
326 | const email = new Email();
|
327 |
|
328 | email
|
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 |
|
345 | The 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 |
|
358 | The 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
|
363 | const Email = require('email-templates');
|
364 |
|
365 | const email = new Email();
|
366 |
|
367 | email
|
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
|
378 | const Email = require('email-templates');
|
379 |
|
380 | const email = new Email();
|
381 | const locals = { name: 'Elon' };
|
382 |
|
383 | Promise
|
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 |
|
397 | Out 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 |
|
399 | We strongly suggest to pre-cache your templates with [cache-pug-templates][] (if you're using the default [Pug][] template engine).
|
400 |
|
401 | If 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 |
|
403 | Note 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 |
|
407 | All 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
|
412 | const Email = require('email-templates');
|
413 |
|
414 | const email = new Email({
|
415 | message: {
|
416 | from: 'niftylettuce@gmail.com'
|
417 | },
|
418 | transport: {
|
419 | jsonTransport: true
|
420 | },
|
421 | i18n: {} // <------ HERE
|
422 | });
|
423 |
|
424 | email
|
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 |
|
441 | Then slightly modify your templates to use localization functions.
|
442 |
|
443 | > `html.pug`:
|
444 |
|
445 | ```pug
|
446 | p= `${t('Hi')} ${name},`
|
447 | p= t('Welcome to Mars, the red planet.')
|
448 | ```
|
449 |
|
450 | > `subject.pug`:
|
451 |
|
452 | ```pug
|
453 | p= `${t('Hi')} ${name}, ${t('welcome to Mars')}`
|
454 | ```
|
455 |
|
456 | Note that if you use [Lad][], you have a built-in filter called `translate`:
|
457 |
|
458 | ```pug
|
459 | p: :translate(locale) Welcome to Mars, the red planet.
|
460 | ```
|
461 |
|
462 | #### Localization using Handlebars template engine
|
463 |
|
464 | If you are using handlebars and you are using localization files with named values, you will quickly see that
|
465 | there is no way to properly call the `t` function in your template and specify named values.
|
466 |
|
467 | If, 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 |
|
476 | And 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 |
|
485 | This would not work because the second argument sent by handlebars to the function would be a handlebar helper
|
486 | options object instead of just the named values.
|
487 |
|
488 | A possible workaround you can use is to introduce your own translation helper in your template locals:
|
489 |
|
490 | ```js
|
491 | email
|
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 |
|
515 | Then 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 |
|
526 | If you wish to have only a text-based version of your email you can simply pass the option `textOnly: true`.
|
527 |
|
528 | Regardless if you use the `htmlToText` option or not (see next example), it will still render only a text-based version.
|
529 |
|
530 | ```js
|
531 | const Email = require('email-templates');
|
532 |
|
533 | const email = new Email({
|
534 | message: {
|
535 | from: 'niftylettuce@gmail.com'
|
536 | },
|
537 | transport: {
|
538 | jsonTransport: true
|
539 | },
|
540 | textOnly: true // <----- HERE
|
541 | });
|
542 |
|
543 | email
|
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 |
|
559 | You can pass an option to prefix subject lines with a string, which is super useful for deciphering development / staging / production environment emails.
|
560 |
|
561 | For example, you could make it so on non-production environments the email is prefixed with a `[DEVELOPMENT] Some Subject Line Here`.
|
562 |
|
563 | You 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 |
|
565 | Simply 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
|
568 | const Email = require('email-templates');
|
569 |
|
570 | const env = process.env.NODE_ENV || 'development';
|
571 |
|
572 | const 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 |
|
587 | If 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 |
|
589 | You may also set `config.htmlToText: false` to force the usage of the `text` template file.
|
590 |
|
591 | ```js
|
592 | const Email = require('email-templates');
|
593 |
|
594 | const email = new Email({
|
595 | message: {
|
596 | from: 'niftylettuce@gmail.com'
|
597 | },
|
598 | transport: {
|
599 | jsonTransport: true
|
600 | },
|
601 | htmlToText: false // <----- HERE
|
602 | });
|
603 |
|
604 | email
|
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 |
|
627 | 1. 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 |
|
641 | 2. 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 |
|
663 | You can configure your Email instance to have default message options, such as a default "From", an unsubscribe header, etc.
|
664 |
|
665 | For 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
|
670 | const Email = require('email-templates');
|
671 |
|
672 | const 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 |
|
690 | You can pass a custom `config.render` function which accepts two arguments `view` and `locals` and must return a `Promise`.
|
691 |
|
692 | Note 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 |
|
694 | If you wanted to read a stored EJS template from MongoDB, you could do something like:
|
695 |
|
696 | ```js
|
697 | const ejs = require('ejs');
|
698 |
|
699 | const 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 |
|
720 | As 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 |
|
722 | For both `email.send` and `email.render`, the `template` option passed can be a relative path or absolute:
|
723 |
|
724 | > Relative example:
|
725 |
|
726 | ```js
|
727 | email
|
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
|
744 | const path = require('path');
|
745 |
|
746 | // ...
|
747 |
|
748 | email
|
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 |
|
764 | The `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
|
769 | const email = new Email({
|
770 | // ...
|
771 | preview: {
|
772 | open: {
|
773 | app: 'firefox',
|
774 | wait: false
|
775 | }
|
776 | }
|
777 | });
|
778 | ```
|
779 |
|
780 |
|
781 | ## Options
|
782 |
|
783 | For 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 |
|
816 | You can use any [nodemailer][] plugin. Simply pass an existing transport instance as `config.transport`.
|
817 |
|
818 | You should add the [nodemailer-base64-to-s3][] plugin to convert base64 inline images to actual images stored on Amazon S3 and Cloudfront.
|
819 |
|
820 | When 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
|
823 | const 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 |
|
835 | We 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 |
|
843 | See the [Releases](https://github.com/forwardemail/email-templates/releases) page for an up to date changelog.
|
844 |
|
845 | ### v8.0.0
|
846 |
|
847 | We 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 |
|
862 | We 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 |
|
889 | In 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 |
|
893 | See 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 |
|
899 | 1. You need to have Node v6.4.0+, we recommend using [nvm](https://github.com/creationix/nvm) to manage your Node versions.
|
900 |
|
901 | 2. 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 |
|
917 | 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.
|
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 |
|
929 | 4. Localized template directories are no longer supported. We now support i18n translations out of the box. See [Localization](#localization) for more info.
|
930 |
|
931 | 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](#basic) usage documentation above for an example.
|
932 |
|
933 | 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](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 |
|
935 | 7. If you wish to send emails in development or test environment (disabled by default), set `options.send` to `true`.
|
936 |
|
937 |
|
938 | ## Tip
|
939 |
|
940 | Instead 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 |