MailTime
"Mail-Time" is NPM package for mail queue management. Build on top of the nodemailer
package. Mail-Time made for single-server and horizontally scaled multi-server setups in mind.
Every MailTime
instance can have type
configured as Server or Client. Server type of MailTime
is great for creating an emailing micro-service app.
The main difference between Server and Client type
is that the Server handles the queue and sends email. While the Client only adds emails into the queue.
ToC
- How it works?
- Features
- Installation
- Meteor.js usage
- Usage examples
- Require/Import
mail-time
- Create NodeMailer's transports
- Initiate
mail-time
- Initiate two
MailTime
instances within the single app - Use templates
- Different storage configurations:
- Require/Import
- API
- Custom Templates
- Running tests
Main features:
- 👨🔬 ~94% tests coverage;
- 📦 Two simple dependencies, written from scratch for top performance;
- 🏢 Synchronize email queue across multiple (horizontally scaled) servers;
- 💪 Bulletproof design, built-in retries.
How does it work?
Redundant solution for email transmission.
Single point of failure
Issue - mitigate a single point of failure via persistent queue and re-send attempts
|----------------| |------| |------------------| | Other mailer | ------> | SMTP | ------> | ^_^ Happy user | |----------------| |------| |------------------| The scheme above will work as long as SMTP service is available or connection between your server and SMPT is up. Once network failure occurs or SMTP service is down - users won't be happy |----------------| \ / |------| |------------------| | Other mailer | --X---> | SMTP | ------> | 0_o Disappointed | |----------------| / \ |------| |------------------| ^- email lost in vain Single SMTP solution may work in case of network or other failures As long as MailTime has not received confirmation what email is sent it will keep the letter in the queue and retry to send it again |----------------| / |------| |------------------| | Mail Time | --X---> | SMTP | ------> | ^_^ Happy user | |---^------------| / |------| |------^-----------| \-------------/ ^- We will try later / \- put it back into queue / \----------Once connection is back ------/
Multiple SMTP providers
Rotate email transports by using multiple SMTP providers. MailTime support two strategies backup
(rotate when failed) and balancer
(round-robin rotation)
|--------| /--X--| SMTP 1 | / ^ |--------| / \--- Retry with next provider |----------------|/ |--------| |------------------| | Mail Time | ---X--> | SMTP 2 | /->| ^_^ Happy user | |----------------|\ ^ |--------| / |------------------| \ \--- Retry / \ |--------| / \---->| SMTP 3 |--/ |--------|
Sending emails from cluster of servers
It is common to have horizontally scaled "Cluster" of servers for load-balancing and for durability.
Most modern application has scheduled or recurring emails. For example, once a day — with recent news and updates. It won't be an issue with a single server setup — the server would send emails at a daily interval via timer or CRON. But in "Cluster" implementation — each server will attempt to send the same email. MailTime built to avoid sending the same email multiple times to a user from horizontally scaled applications.
For the maximum durability and agility each Application Server can run MailTime in the "Server" mode:
|===================THE=CLUSTER===================| |=QUEUE=| | |----------| |----------| |----------| | | | |--------| | | App | | App | | App | | | |-->| SMTP 1 |------\ | | Server 1 | | Server 2 | | Server 3 | | | | |--------| \ | |-----\----| |----\-----| |----\-----| | | | |-------------| | \---------------\----------------\----------> | |--------| | ^_^ | | | | |-->| SMTP 2 |-->| Happy users | | Each "App Server" | | | |--------| |-------------| | runs MailTime as a "Server" | | | / | for the maximum durability | | | |--------| / | | | |-->| SMTP 3 |-----/ | | | | |--------| |=================================================| |=======|
To split roles MailTime can run on a dedicated machine as micro-service. This case is great for private email servers with implemented authentication via rDNS and PTR records:
|===================THE=CLUSTER===================| |=QUEUE=| |===Mail=Time===| | |----------| |----------| |----------| | | | | | |--------| | | App | | App | | App | | | | | Micro-service |-->| SMTP 1 |------\ | | Server 1 | | Server 2 | | Server 3 | | | | | running | |--------| \ | |-----\----| |----\-----| |----\-----| | | | | MailTime as | |-------------| | \---------------\----------------\----------> | | "Server" only | |--------| | ^_^ | | | | | | sending |-->| SMTP 2 |-->| Happy users | | Each "App Server" runs MailTime as | | | | emails | |--------| |-------------| | a "Client" only placing emails to the queue. | | <-------- | / | | | --------> | |--------| / | | | | | |-->| SMTP 3 |-----/ | | | | | | |--------| |=================================================| |=======| |===============|
Features
- Email Queue - Managed via MongoDB, Redis, or Custom Queue. Storage-based queue will survive server reboots and failures
- Made for horizontally scaled multi-server setups - MailTime is made to run in multi-server environments, like "Clusters", multiple app instances, load balanced solutions, and replications. MailTime is the perfect fit for applications scaled on a single machine, multiple virtual servers, multiple "bare metal" servers, within single or multiple data centers
- Email concatenation - Reduce amount of sent emails to a single user with concatenation, and avoid mistakenly duplicated emails. When "email concatenation" is enabled the same emails (checked by addressee and content) won't be sent twice. If emails are sent multiple times, due to issues in logic or application failures, - enable "email concatenation" to solve this behavior
- Multiple NodeMailer/SMTP transports — Support for multiple SMPT transports implemented in two modes -
backup
andbalancing
. Use this feature to reduce the cost of SMTP services and add extra layer of durability. When one of the transports is failing to send an email —mail-time
will switch to the next one - Sending retries — Built-in retries for failed to send emails due to network or other failures
- Templating — Built with support of Mustache-like placeholders, see templating docs
Installation
To implement Server functionality — begin with installing nodemailer
, although this package meant to be used with nodemailer
, it's not added as the dependency, as nodemailer
not needed by Client, and to give freedom to choose nodemailer
's version to fit every project needs:
npm install --save nodemailer
Install MailTime package:
# for node@>=14.20.0 npm install --save mail-time # for node@<14.20.0 npm install --save mail-time@=1.3.4 # for node@<8.9.0 npm install --save mail-time@=0.1.7
Basic usage
Setup Nodemailer's transports, Queue storage, and MailTime instance
Steps to get started
See steps 1-4 below to learn about different parts of MailTime library and how it can get used. From configuration options to sending email
- Require
mail-time
package - Create NodeMailer's transports
- Initiate
mail-time
server- a. Connect to Redis; Or
- b. Connect to MongoDB; And
- c. [optionally] initiate
mail-time
as client
- Start sending emails
1. Require package
1// import as ES Module 2import { MailTime, MongoQueue, RedisQueue } from 'mail-time'; 3 4// require as CommonJS 5const { MailTime, MongoQueue, RedisQueue } = require('mail-time');
2. Create NodeMailer's transports
For compatibility and flexibility MailTime has no dependency on nodemailer
it should be installed and imported manually. Create one or more "SMTP transports" before initializing new MailTime instance.
For details and full list of options available in .createTransport()
see nodemailer
docs
1// transports.js 2import nodemailer from 'nodemailer'; 3// Use DIRECT transport 4// and enable sending email from localhost 5// install "nodemailer-direct-transport" NPM package: 6import directTransport from 'nodemailer-direct-transport'; 7 8const transports = []; 9const directTransportOpts = { 10 pool: false, 11 direct: true, 12 name: 'mail.example.com', 13 from: 'no-reply@example.com', 14}; 15transports.push(nodemailer.createTransport(directTransport(directTransportOpts))); 16// IMPORTANT: Add `.options` to a newly created transport, 17// this is necessary to make sure options are available to MailTime package: 18transports[0].options = directTransportOpts; 19 20// Private SMTP 21transports.push(nodemailer.createTransport({ 22 host: 'smtp.example.com', 23 from: 'no-reply@example.com', 24 auth: { 25 user: 'no-reply', 26 pass: 'xxx' 27 }, 28})); 29 30// Google Apps SMTP 31transports.push(nodemailer.createTransport({ 32 host: 'smtp.gmail.com', 33 from: 'no-reply@mail.example.com', 34 auth: { 35 user: 'no-reply@mail.example.com', 36 pass: 'xxx' 37 }, 38})); 39 40// Mailing service (SparkPost as example) 41transports.push(nodemailer.createTransport({ 42 host: 'smtp.sparkpostmail.com', 43 port: 587, 44 from: 'no-reply@mail2.example.com', 45 auth: { 46 user: 'SMTP_Injection', 47 pass: 'xxx' 48 }, 49})); 50 51export { transports };
3. Initiate mail-time
Create new instance of MailTime in the Server mode, — it will be able to send and add emails to the queue.
3a. Initiate and connect to Redis
Connecting to Redis before initiating new MailTime
instance:
1// mail-queue.js 2import { MailTime, RedisQueue } from 'mail-time'; 3import { createClient } from 'redis'; 4import { transports } from './transports.js'; 5 6// Use REDIS_URL environment variable to store connection string to MongoDB 7// example: "REDIS_URL=redis://127.0.0.1:6379/myapp node mail-micro-service.js" 8const redisClient = await createClient({ url: process.env.REDIS_URL }).connect(); 9const mailQueue = new MailTime({ 10 transports, 11 queue: new MongoQueue({ 12 client: redisClient, 13 }), 14 josk: { 15 adapter: { 16 type: 'redis', 17 client: redisClient, 18 } 19 }, 20 template: MailTime.Template // Use default template 21 from(transport) { 22 // To pass spam-filters `from` field should be correctly set 23 // for each transport, check `transport` object for more options 24 return `"Awesome App" <${transport.options.from}>`; 25 }, 26 onError(error, email, details) { 27 console.log(`Email "${email.mailOptions.subject}" wasn't sent to ${email.mailOptions.to}`, error, details); 28 }, 29 onSent(email, details) { 30 console.log(`Email "${email.mailOptions.subject}" successfully sent to ${email.mailOptions.to}`, details); 31 }, 32}); 33 34export { mailQueue };
3b. Initiate and connect to MongoDB
Connecting to MongoDB before initiating new MailTime
instance:
1// mail-queue.js 2import { MailTime, MongoQueue } from 'mail-time'; 3import { MongoClient } from 'mongodb'; 4import { transports } from './transports.js'; 5 6// Use MONGO_URL environment variable to store connection string to MongoDB 7// example: "MONGO_URL=mongodb://127.0.0.1:27017/myapp node mail-micro-service.js" 8const mongodb = (await MongoClient.connect(process.env.MONGO_URL)).db('database'); 9const mailQueue = new MailTime({ 10 transports, 11 queue: new MongoQueue({ 12 db: mongodb, 13 }), 14 josk: { 15 adapter: { 16 type: 'mongo', 17 db: mongodb, 18 } 19 }, 20 template: MailTime.Template // Use default template 21 from(transport) { 22 // To pass spam-filters `from` field should be correctly set 23 // for each transport, check `transport` object for more options 24 return `"Awesome App" <${transport.options.from}>`; 25 }, 26 onError(error, email, details) { 27 console.log(`Email "${email.mailOptions.subject}" wasn't sent to ${email.mailOptions.to}`, error, details); 28 }, 29 onSent(email, details) { 30 console.log(`Email "${email.mailOptions.subject}" successfully sent to ${email.mailOptions.to}`, details); 31 }, 32}); 33 34export { mailQueue };
3c. Optionally create Client type of MailTime
Only one MailTime
Server instance required to send email. In the other parts of an app (like UI units or in sub-apps) use mail-time
in the Client mode to add emails to queue
1// mail-queue.js 2import { MailTime, RedisQueue } from 'mail-time'; 3import { createClient } from 'redis'; 4 5const mailQueue = new MailTime({ 6 type: 'client', 7 queue: new RedisQueue({ 8 client: await createClient({ url: 'redis://url' }).connect() 9 }), 10}); 11 12export { mailQueue };
4. Send email
Import created mailQueue
where needed and call .sendMail()
method. See NodeMailer's message configuration documentation for details
1import { mailQueue } from './mail-queue.js'; 2 3await mailQueue.sendMail({ 4 to: 'user@gmail.com', 5 subject: 'You\'ve got an email!', 6 text: 'Plain text message', 7 html: '<h1>HTML</h1><p>Styled message</p>' 8});
Using MongoDB for queue and scheduler
MailTime uses separate storage for Queue management and Scheduler. In the example below MongoDB is used for both
1import { MailTime, MongoQueue } from 'mail-time'; 2import { MongoClient } from 'mongodb'; 3import { transports } from './transports.js'; 4 5const db = (await MongoClient.connect('mongodb://url')).db('database'); 6const mailQueue = new MailTime({ 7 queue: new MongoQueue({ 8 db: db, 9 }), 10 josk: { 11 adapter: { 12 type: 'mongo', 13 db: db, 14 } 15 }, 16 transports, 17 from(transport) { 18 // To pass spam-filters `from` field should be correctly set 19 // for each transport, check `transport` object for more options 20 return `"Awesome App" <${transport.options.from}>`; 21 } 22});
Using MongoDB for queue and Redis for scheduler
MailTime uses separate storage for Queue management and Scheduler. In the example below MongoDB is used for queue and Redis is used for scheduler
1import { MailTime, MongoQueue } from 'mail-time'; 2import { MongoClient } from 'mongodb'; 3import { createClient } from 'redis'; 4import { transports } from './transports.js'; 5 6const mailQueue = new MailTime({ 7 queue: new MongoQueue({ 8 db: (await MongoClient.connect('mongodb://url')).db('database'), 9 }), 10 josk: { 11 adapter: { 12 type: 'redis', 13 client: await createClient({ url: 'redis://url' }).connect(), 14 } 15 }, 16 transports, 17 from(transport) { 18 return `"Awesome App" <${transport.options.from}>`; 19 } 20});
Using Redis for queue and MongoDB for scheduler
MailTime uses separate storage for Queue management and Scheduler. In the example below Redis is used for queue and MongoDB is used for scheduler
1import { MailTime, RedisQueue } from 'mail-time'; 2import { MongoClient } from 'mongodb'; 3import { createClient } from 'redis'; 4import { transports } from './transports.js'; 5 6const mailQueue = new MailTime({ 7 queue: new RedisQueue({ 8 client: await createClient({ url: 'redis://url' }).connect(), 9 }), 10 josk: { 11 adapter: { 12 type: 'mongo', 13 db: (await MongoClient.connect('mongodb://url')).db('database'), 14 } 15 }, 16 transports, 17 from(transport) { 18 return `"Awesome App" <${transport.options.from}>`; 19 } 20});
Using Redis for queue and scheduler
MailTime uses separate storage for Queue management and Scheduler. In the example below Redis is used for both
1import { MailTime, RedisQueue } from 'mail-time'; 2import { MongoClient } from 'mongodb'; 3import { createClient } from 'redis'; 4import { transports } from './transports.js'; 5 6const redisClient = await createClient({ url: 'redis://url' }).connect(); 7const mailQueue = new MailTime({ 8 queue: new RedisQueue({ 9 client: redisClient, 10 }), 11 josk: { 12 adapter: { 13 type: 'redis', 14 client: redisClient, 15 } 16 }, 17 transports, 18 from(transport) { 19 return `"Awesome App" <${transport.options.from}>`; 20 } 21});
Two MailTime
instances usage example
Create two MailTime
instances with different settings. One for urgent (e.g. "transactional" emails), and another one for other types of emails (e.g. "marketing" emails)
1import { MailTime, RedisQueue } from 'mail-time'; 2import { createClient } from 'redis'; 3import { transports } from './transports.js'; 4const redisClient = await createClient({ url: 'redis://url' }).connect(); 5 6// CREATE mailQueue FOR NON-URGENT EMAILS WHICH IS OKAY TO CONCATENATE 7const mailQueue = new MailTime({ 8 queue: new RedisQueue({ 9 client: redisClient, 10 }), 11 transports, 12 strategy: 'backup', 13 failsToNext: 1, 14 concatEmails: true, 15 josk: { 16 adapter: { 17 type: 'redis', 18 client: redisClient 19 }, 20 zombieTime: 120000 21 } 22}); 23 24// CREATE mailInstantQueue FOR TRANSACTIONAL EMAILS AND ALERTS 25const mailInstantQueue = new MailTime({ 26 queue: new RedisQueue({ 27 client: redisClient, 28 prefix: 'instant' 29 }), 30 transports, 31 prefix: 'instant', 32 retryDelay: 2000, 33 strategy: 'backup', 34 failsToNext: 1, 35 concatEmails: false, 36 josk: { 37 adapter: { 38 type: 'redis', 39 client: redisClient 40 }, 41 zombieTime: 20000 42 } 43}); 44 45await mailQueue.sendMail({ 46 to: 'user@gmail.com', 47 subject: 'You\'ve got an email!', 48 text: 'Plain text message', 49 html: '<h1>HTML</h1><p>Styled message</p>' 50}); 51 52await mailInstantQueue.sendMail({ 53 to: 'user@gmail.com', 54 subject: 'Sign in request', 55 text: 'Your OTP login code: xxxx:', 56 html: '<h1>Code:</h1><code>XXXX</code>' 57});
Passing variables to the template
All options passed to the .sendMail()
method are available inside text
, html
, and global templates
1const templates = { 2 global: '<html xmlns="http://www.w3.org/1999/xhtml"><head><title>{{subject}}</title></head><body>{{{html}}}<footer>Message sent to @{{username}} user ({{to}})</footer></body></html>', 3 signInCode: { 4 text: 'Hello @{{username}}! Here\'s your login code: {{code}}', 5 html: `<h1>Sign-in request</h1><p>Hello @{{username}}! <p>Copy your login code below:</p> <pre><code>{{code}}</code></pre>` 6 } 7}; 8 9const mailQueue = new MailTime({ 10 queue: new RedisQueue({ /* ... */ }), 11 template: templates.global 12}); 13 14await mailQueue.sendMail({ 15 to: 'user@gmail.com', 16 subject: 'Sign-in request', 17 username: 'johndoe', 18 code: 'XXXXX-YY', 19 text: templates.signInCode.text, 20 html: templates.signInCode.html 21});
API
All available constructor options and .sendMail()
method API overview
new MailTime(opts)
constructor
opts
{object} - Configuration objectopts.type
{string} - [Optional]client
orserver
, default -server
opts.queue
{RedisQueue|MongoQueue|CustomQueue} - Queue storage driver instanceopts.transports
{[object]} - [Required for "server"] An array ofnodemailer
's transports, returned fromnodemailer.createTransport({})
. Required for{type: 'server'}
opts.josk
{object} - [Required for "server"]JoSk
package optionsopts.josk.adapter
{object|RedisAdapter|MongoAdapter|CustomAdapter} - Config object or Adapter instanceopts.josk.adapter.type
{string} - One ofmongo
orredis
; Passjosk.adapter.type
to avoid burden of creating Adapter instance manuallyopts.josk.adapter.client
{RedisClient} - RedisClient instanceopts.josk.adapter.db
{Db} - Mongo's Db instanceopts.josk[option]
{mix} - Any other options passed toJoSk
instanceopts.from
{function} - [Optional] A function which returns string offrom
field, format:"MyApp" <user@example.com>
opts.strategy
{string} - [Optional]backup
orbalancer
, default -backup
. If set tobackup
, first transport will be used unless failed to sendfailsToNext
times. If set tobalancer
- transports will be used equally in round robin chainopts.failsToNext
{number} - [Optional] After how many failed "send attempts" switch to the next transport, applied only forbackup
strategy, default -4
opts.prefix
{string} - [Optional] Use unique prefixes to create multipleMailTime
instances within the same applicationopts.retries
{number} - [Optional] How many times resend failed emails, default -60
opts.retryDelay
{number} - [Optional] Interval in milliseconds between send re-tries, default -60000
opts.keepHistory
{boolean} - [Optional] By default sent emails not stored in the database. Set{ keepHistory: true }
to keep queue task as it is in the database, default -false
opts.concatEmails
{boolean} - [Optional] Concatenate email byto
field (e.g. to the same addressee), default -false
opts.concatSubject
{string} - [Optional] Email subject used in concatenated email, default -Multiple notifications
opts.concatDelimiter
{string} - [Optional] HTML or plain string delimiter used between concatenated email, default -<hr>
opts.concatDelay
{number} - [Optional] Time in milliseconds while emails are waiting to be concatenated, default -60000
opts.revolvingInterval
{number} - [Optional] Interval in milliseconds in between queue checks, default -256
opts.template
{string} - [Optional] Mustache-like template, default -{{{html}}}
, all options passed tosendMail
is available in Template, liketo
,subject
,text
,html
or any other custom option. Use{{opt}}
for string placeholders and{{{opt}}}
for html placeholdersopts.onError(error, email, details)
{function} - [Optional] called when email has failed to get sent and exhausted all send attempts (opts.retries
), called with 3 arguments:error
{Error|object} - Error objectemail
{object} - email's objectdetails
{object} - not always present, details from SMTP protocol
opts.onSent(email, details)
{function} - [Optional] called when email was successfully handed over to receiving/recipient's SMTP server, called with 2 arguments:email
{object} - email's objectdetails
{object} - not always present, details from SMTP server/protocol
1import { MailTime, MongoQueue, RedisQueue } from 'mail-time'; 2import nodemailer from 'nodemailer'; 3import { createClient } from 'redis'; 4 5const redisClient = await createClient({ url: 'redis://url' }).connect(); 6 7const mailQueue = new MailTime({ 8 type: 'server', 9 strategy: 'backup', 10 prefix: 'appMailQueue', 11 transports: [nodemailer.createTransport({/* ... */})], 12 failsToNext: 4, 13 retries: 60, 14 retryDelay: 60000, 15 keepHistory: false, 16 concatEmails: false, 17 concatDelay: 60000, 18 concatDelimiter: '<hr>', 19 concatSubject: 'Multiple notifications', 20 revolvingInterval: 256, 21 template: '{{{html}}}', 22 queue: new RedisQueue({ 23 client: redisClient, 24 prefix: 'appMailQueue', 25 }), 26 josk: { 27 adapter: { 28 type: 'redis', 29 client: redisClient, 30 } 31 }, 32 from(transport) { 33 // To pass spam-filters `from` field should be correctly set 34 // for each transport, check `transport` object for more options 35 return `"App Name" <${transport.options.from}>`; 36 }, 37 onError(error, email, details) { 38 console.log(`Email "${email.mailOptions.subject}" wasn't sent to ${email.mailOptions.to}`, error, details); 39 }, 40 onSent(email, details) { 41 console.log(`Email "${email.mailOptions.subject}" successfully sent to ${email.mailOptions.to}`, details); 42 }, 43}); 44 45await mailQueue.sendMail({ 46 to: 'johndoe@example.com', 47 subject: 'Email subject', 48 text: 'You have got email!', 49 html: '<p>You have got email!</p>', 50});
new RedisQueue(opts)
constructor
Create Redis Queue instance. Use for opts.queue
when creating MailTime instance
opts
{object} - Configuration objectopts.client
{RedisClient} - Required, Redis'esRedisClient
instance, like one returned fromawait redis.createClient().connect()
methodopts.prefix
{string} - Optional prefix for scope isolation; use when creating multipleMailTime
instances within the single application
1import { MailTime, RedisQueue } from 'mail-time'; 2import { createClient } from 'redis'; 3 4new RedisQueue({ 5 client: await createClient({ url: 'redis://url' }).connect(), 6 prefix: 'appMailQueue', 7});
new MongoQueue(opts)
constructor
Create MongoDB Queue instance. Use for opts.queue
when creating MailTime instance
opts
{object} - Configuration objectopts.db
{Db} - Required, Mongo'sDb
instance, like one returned fromMongoClient#db()
opts.prefix
{string} - Optional prefix for scope isolation; use when creating multipleMailTime
instances within the single application
1import { MailTime, MongoQueue } from 'mail-time'; 2import { MongoClient } from 'mongodb'; 3 4new MongoQueue({ 5 db: (await MongoClient.connect('mongodb://url')).db('database'), 6 prefix: 'appMailQueue', 7});
sendMail(opts)
Add email to the queue. Returns Promise<string>
unique email's uuid
opts
{object} - Configuration objectopts.sendAt
{number} - When email should be sent, default -Date.now()
opts.template
{string} - Email specific template, this will override default template passed toMailTime
constructoropts.concatSubject
{string} - Email specific concatenation subject, this will override default concatenation subject passed toMailTime
constructoropts[key]
{mix} - Other custom and NodeMailer specific options, liketext
,html
andto
, learn more here. Note: ifattachments
are used viapath
— file must exists on all micro-services servers
cancelMail(uuid)
Remove email from queue. Returns Promise<boolean>
— true
if cancelled or false
if not found, was sent, or was cancelled previously. Throws Error
uuid
{string|promise} — email'suuid
returned from.sendEmail()
method
1import { mailQueue } from './mail-queue.js'; 2 3const uuid = await mailQueue.sendMail({ 4 to: 'johndoe@example.com', 5 subject: 'Email subject', 6 text: 'You have got email!', 7 html: '<p>You have got email!</p>', 8}); 9 10await mailQueue.cancelMail(uuid);
static MailTime.Template
Simple and bulletproof HTML template, see its source. Usage example:
1import { MailTime, MongoQueue, RedisQueue } from 'mail-time'; 2 3// Make it default 4const mailQueue = new MailTime({ 5 /* .. */ 6 template: MailTime.Template 7}); 8 9// For single letter 10mailQueue.sendMail({ 11 /* .. */ 12 template: MailTime.Template 13});
Template Example
Pass custom template via template
property to .sendMail()
method
1mailQueue.sendMail({ 2 to: 'user@gmail.com', 3 userName: 'Mike', 4 subject: 'Sign up confirmation', 5 text: 'Hello {{userName}}, \r\n Thank you for registration \r\n Your login: {{to}}', 6 html: '<div style="text-align: center"><h1>Hello {{userName}}</h1><p><ul><li>Thank you for registration</li><li>Your login: {{to}}</li></ul></p></div>', 7 template: '<body>{{{html}}}</body>' 8});
Testing
- Clone this package
- Start local or obtain URLs for remote MongoDB and Redis servers
- In Terminal (Console) go to directory where package was cloned
- Then run:
# Before running tests make sure NODE_ENV === development # Install NPM dependencies npm install --save-dev # DEFAULT RUN REDIS_URL="redis://127.0.0.1:6379" MONGO_URL="mongodb://127.0.0.1:27017/npm-mail-time-test-001" npm test # OPTIONALLY RUN WITH CUSTOM DOMAIN EMAIL_DOMAIN="your-domain.com" REDIS_URL="redis://127.0.0.1:6379" MONGO_URL="mongodb://127.0.0.1:27017/npm-mail-time-test-001" npm test # IF SOME TESTS ARE FAILING: ENABLE DEBUG DEBUG="true" REDIS_URL="redis://127.0.0.1:6379" MONGO_URL="mongodb://127.0.0.1:27017/npm-mail-time-test-001" npm test # Be patient, tests are taking around 8 mins
Support this project:
- Upload and share files using ☄️ meteor-files.com — Continue interrupted file uploads without losing any progress. There is nothing that will stop Meteor from delivering your file to the desired destination
- Use ▲ ostr.io for Server Monitoring, Web Analytics, WebSec, Web-CRON and SEO Pre-rendering of a website
- Star on GitHub
- Star on NPM
- Star on Atmosphere
- Sponsor maintainer via GitHub — support open source with one-time contribution or on a regular basis
- Sponsor veliovgroup via GitHub — support company behind this package
- Support via PayPal — support our open source contributions