mail-time 1.2.6 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +111 -26
- package/index.js +123 -138
- package/package.json +10 -10
- package/CHANGELOG.md +0 -1
- package/HISTORY.md +0 -1
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://github.com/sponsors/
|
|
1
|
+
[](https://github.com/sponsors/veliovgroup)
|
|
2
2
|
[](https://paypal.me/veliovgroup)
|
|
3
3
|
<a href="https://ostr.io/info/built-by-developers-for-developers">
|
|
4
4
|
<img src="https://ostr.io/apple-touch-icon-60x60.png" height="20">
|
|
@@ -14,6 +14,12 @@ Every `MailTime` instance can be configured to be a *Server* or *Client*.
|
|
|
14
14
|
Main difference of *Server* from *Client* - *Server* handles queue and actually sends email.
|
|
15
15
|
While *Client* is only put emails into the queue.
|
|
16
16
|
|
|
17
|
+
"Mail-Time" is a micro-service package for mail queue, with *Server* and *Client* APIs. Build on top of the [`nodemailer`](https://github.com/nodemailer/nodemailer) package.
|
|
18
|
+
|
|
19
|
+
Every `MailTime` instance can get configured as *Server* or *Client*.
|
|
20
|
+
|
|
21
|
+
The main difference between *Server* and *Client* modes is that the *Server* handles the queue and __sends__ email. While the *Client* only __adds__ emails into the queue.
|
|
22
|
+
|
|
17
23
|
## ToC
|
|
18
24
|
|
|
19
25
|
- [How it works?](https://github.com/veliovgroup/Mail-Time#how-it-works)
|
|
@@ -45,7 +51,7 @@ Redundant solution for email transmission.
|
|
|
45
51
|
|
|
46
52
|
### Single point of failure
|
|
47
53
|
|
|
48
|
-
Issue - classic solution with
|
|
54
|
+
Issue - classic solution with a single point of failure:
|
|
49
55
|
|
|
50
56
|
```ascii
|
|
51
57
|
|----------------| |------| |------------------|
|
|
@@ -93,11 +99,11 @@ Backup scheme with multiple SMTP providers
|
|
|
93
99
|
|
|
94
100
|
### Cluster issue
|
|
95
101
|
|
|
96
|
-
|
|
102
|
+
It is common to create a "Cluster" of servers to balance the load and add a durability layer for horizontal scaling of quickly growing applications.
|
|
97
103
|
|
|
98
|
-
|
|
104
|
+
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. While in "Cluster" implementation — each server will attempt to send the same email. In such cases, users will receive multiple emails with the same content. We built MailTime to address this and other similar issues.
|
|
99
105
|
|
|
100
|
-
Here is how
|
|
106
|
+
Here is how this issue is solved by using MailTime:
|
|
101
107
|
|
|
102
108
|
```ascii
|
|
103
109
|
|===================THE=CLUSTER===================| |=QUEUE=| |===Mail=Time===|
|
|
@@ -117,17 +123,17 @@ Here is how we solve this issue:
|
|
|
117
123
|
|
|
118
124
|
## Features
|
|
119
125
|
|
|
120
|
-
- Queue - Managed via MongoDB,
|
|
126
|
+
- Queue - Managed via MongoDB, will survive server reboots and failures
|
|
121
127
|
- Support for multiple server setups - "Cluster", Phusion Passenger instances, Load Balanced solutions, etc.
|
|
122
128
|
- Emails concatenation by addressee email - Reduce amount of sent emails to a single user with concatenation, and avoid mistakenly doubled emails
|
|
123
129
|
- When concatenation is enabled - Same emails won't be sent twice, if for any reason, due to bad logic or application failure emails are sent twice or more times - this is solution to solve this annoying behavior
|
|
124
|
-
- Balancing for multiple nodemailer's transports, two modes - `backup` and `balancing`.
|
|
130
|
+
- Balancing for multiple nodemailer's transports, two modes - `backup` and `balancing`. This is the most useful feature — allowing to reduce the cost of SMTP services and add extra layer of durability. If one transport failing to send an email `mail-time` will switch to the next one
|
|
125
131
|
- Sending retries for network and other failures
|
|
126
|
-
-
|
|
132
|
+
- Templating support with [Mustache](https://mustache.github.io/)-like placeholders
|
|
127
133
|
|
|
128
134
|
## Installation
|
|
129
135
|
|
|
130
|
-
|
|
136
|
+
To implement Server functionality — as a first step install `nodemailer`, although this package meant to be used with `nodemailer`, it's not added as the dependency, as `nodemailer` not needed by Client, and you're free to choose `nodemailer`'s version to fit your project needs:
|
|
131
137
|
|
|
132
138
|
```shell
|
|
133
139
|
npm install --save nodemailer
|
|
@@ -151,14 +157,14 @@ Require package:
|
|
|
151
157
|
const MailTime = require('mail-time');
|
|
152
158
|
```
|
|
153
159
|
|
|
154
|
-
Create nodemailer's transports (see [nodemailer docs](https://github.com/nodemailer/nodemailer/tree/v2#setting-up)):
|
|
160
|
+
Create nodemailer's transports (see [`nodemailer` docs](https://github.com/nodemailer/nodemailer/tree/v2#setting-up)):
|
|
155
161
|
|
|
156
162
|
```js
|
|
157
163
|
const transports = [];
|
|
158
164
|
const nodemailer = require('nodemailer');
|
|
159
165
|
|
|
160
166
|
// Use DIRECT transport
|
|
161
|
-
//
|
|
167
|
+
// and enable sending email from localhost
|
|
162
168
|
// install "nodemailer-direct-transport" NPM package:
|
|
163
169
|
const directTransport = require('nodemailer-direct-transport');
|
|
164
170
|
const directTransportOpts = {
|
|
@@ -204,8 +210,7 @@ transports.push(nodemailer.createTransport({
|
|
|
204
210
|
}));
|
|
205
211
|
```
|
|
206
212
|
|
|
207
|
-
|
|
208
|
-
We will need connect to MongoDB first:
|
|
213
|
+
As the next step initiate `mail-time` in the *Server* mode, it will be able to __send__ and __add__ emails to the queue. Connecting to a MongoDB before initiating `new MailTime` instance:
|
|
209
214
|
|
|
210
215
|
```js
|
|
211
216
|
const MongoClient = require('mongodb').MongoClient;
|
|
@@ -226,7 +231,7 @@ MongoClient.connect(process.env.MONGO_URL, (error, client) => {
|
|
|
226
231
|
from(transport) {
|
|
227
232
|
// To pass spam-filters `from` field should be correctly set
|
|
228
233
|
// for each transport, check `transport` object for more options
|
|
229
|
-
return
|
|
234
|
+
return `"Awesome App" <${transport.options.from}>`;
|
|
230
235
|
},
|
|
231
236
|
concatEmails: true, // Concatenate emails to the same addressee
|
|
232
237
|
concatDelimiter: '<h1>{{{subject}}}</h1>', // Start each concatenated email with it's own subject
|
|
@@ -235,7 +240,7 @@ MongoClient.connect(process.env.MONGO_URL, (error, client) => {
|
|
|
235
240
|
});
|
|
236
241
|
```
|
|
237
242
|
|
|
238
|
-
|
|
243
|
+
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:
|
|
239
244
|
|
|
240
245
|
```js
|
|
241
246
|
const MongoClient = require('mongodb').MongoClient;
|
|
@@ -254,7 +259,7 @@ MongoClient.connect(process.env.MONGO_URL, (error, client) => {
|
|
|
254
259
|
});
|
|
255
260
|
```
|
|
256
261
|
|
|
257
|
-
Send email:
|
|
262
|
+
Send email example:
|
|
258
263
|
|
|
259
264
|
```js
|
|
260
265
|
mailQueue.sendMail({
|
|
@@ -265,33 +270,103 @@ mailQueue.sendMail({
|
|
|
265
270
|
});
|
|
266
271
|
```
|
|
267
272
|
|
|
273
|
+
### Two `MailTime` instances usage example
|
|
274
|
+
|
|
275
|
+
Create two `MailTime` instances with different settings.
|
|
276
|
+
|
|
277
|
+
```js
|
|
278
|
+
// USE FOR NON-URGENT EMAILS WHICH IS OKAY TO CONCATENATE
|
|
279
|
+
const mailQueue = new MailTime({
|
|
280
|
+
db: db,
|
|
281
|
+
interval: 35,
|
|
282
|
+
strategy: 'backup',
|
|
283
|
+
failsToNext: 1,
|
|
284
|
+
concatEmails: true,
|
|
285
|
+
concatThrottling: 16,
|
|
286
|
+
zombieTime: 120000
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// USE FOR TRANSACTIONAL EMAILS AND ALERTS
|
|
290
|
+
const mailInstantQueue = new MailTime({
|
|
291
|
+
db: db,
|
|
292
|
+
prefix: 'instant',
|
|
293
|
+
interval: 2,
|
|
294
|
+
strategy: 'backup',
|
|
295
|
+
failsToNext: 1,
|
|
296
|
+
concatEmails: false,
|
|
297
|
+
zombieTime: 20000
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
mailQueue.sendMail({
|
|
301
|
+
to: 'user@gmail.com',
|
|
302
|
+
subject: 'You\'ve got an email!',
|
|
303
|
+
text: 'Plain text message',
|
|
304
|
+
html: '<h1>HTML</h1><p>Styled message</p>'
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
mailInstantQueue.sendMail({
|
|
308
|
+
to: 'user@gmail.com',
|
|
309
|
+
subject: 'Sign in request',
|
|
310
|
+
text: 'Your OTP login code: xxxx:',
|
|
311
|
+
html: '<h1>Code:</h1><code>XXXX</code>'
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Passing variables to the template
|
|
316
|
+
|
|
317
|
+
All options passed to the `.sendMail()` method is available inside `text`, `html`, and global templates
|
|
318
|
+
|
|
319
|
+
```js
|
|
320
|
+
const templates = {
|
|
321
|
+
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>',
|
|
322
|
+
signInCode: {
|
|
323
|
+
text: 'Hello @{{username}}! Here\'s your login code: {{code}}'
|
|
324
|
+
html: `<h1>Sign-in request</h1><p>Hello @{{username}}! Copy your login code below <pre><code>{{code}}</code></pre>`
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const mailQueue = new MailTime({
|
|
329
|
+
db: db,
|
|
330
|
+
template: templates.global
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
mailQueue.sendMail({
|
|
334
|
+
to: 'user@gmail.com',
|
|
335
|
+
subject: 'Sign-in request',
|
|
336
|
+
username: 'johndoe',
|
|
337
|
+
code: 'XXXXX-YY'
|
|
338
|
+
text: templates.signInCode.text,
|
|
339
|
+
html: templates.signInCode.html
|
|
340
|
+
});
|
|
341
|
+
```
|
|
342
|
+
|
|
268
343
|
## Meteor.js usage:
|
|
269
344
|
|
|
270
|
-
|
|
345
|
+
Mail-Time package can be installed and used within [Meteor.js](https://docs.meteor.com/) via [NPM](https://www.npmjs.com/package/mail-time) or [Atmosphere](https://atmospherejs.com/ostrio/mailer)
|
|
271
346
|
|
|
272
|
-
|
|
347
|
+
### Installation & Import (*via NPM*):
|
|
273
348
|
|
|
274
|
-
Install NPM
|
|
349
|
+
Install [NPM `mail-time` package](https://www.npmjs.com/package/mail-time):
|
|
275
350
|
|
|
276
351
|
```shell
|
|
277
352
|
meteor npm install --save mail-time
|
|
278
353
|
```
|
|
279
354
|
|
|
280
|
-
ES6 Import:
|
|
355
|
+
Meteor.js: ES6 Import NPM package:
|
|
281
356
|
|
|
282
357
|
```js
|
|
283
358
|
import MailTime from 'mail-time';
|
|
284
359
|
```
|
|
285
360
|
|
|
286
|
-
|
|
361
|
+
### Installation & Import (*via Atmosphere*):
|
|
287
362
|
|
|
288
|
-
Install Atmosphere
|
|
363
|
+
Install [Atmosphere `ostrio:mailer` package](https://atmospherejs.com/ostrio/mailer):
|
|
289
364
|
|
|
290
365
|
```shell
|
|
291
366
|
meteor add ostrio:mailer
|
|
292
367
|
```
|
|
293
368
|
|
|
294
|
-
ES6 Import:
|
|
369
|
+
Meteor.js: ES6 Import atmosphere package:
|
|
295
370
|
|
|
296
371
|
```js
|
|
297
372
|
import MailTime from 'meteor/ostrio:mailer';
|
|
@@ -299,6 +374,8 @@ import MailTime from 'meteor/ostrio:mailer';
|
|
|
299
374
|
|
|
300
375
|
### Usage:
|
|
301
376
|
|
|
377
|
+
`mail-time` package usage examples in Meteor.js
|
|
378
|
+
|
|
302
379
|
```js
|
|
303
380
|
import { MongoInternals } from 'meteor/mongo';
|
|
304
381
|
|
|
@@ -338,6 +415,8 @@ const mailQueue = new MailTime({
|
|
|
338
415
|
|
|
339
416
|
## API
|
|
340
417
|
|
|
418
|
+
All available constructor options and `.sendMail()` method API overview
|
|
419
|
+
|
|
341
420
|
### `new MailTime(opts)` constructor
|
|
342
421
|
|
|
343
422
|
- `opts` {*Object*} - Configuration object
|
|
@@ -373,7 +452,7 @@ const mailQueue = new MailTime({
|
|
|
373
452
|
|
|
374
453
|
### `static MailTime.Template`
|
|
375
454
|
|
|
376
|
-
Simple and bulletproof HTML template, see its
|
|
455
|
+
Simple and bulletproof HTML template, see [its source](https://github.com/veliovgroup/Mail-Time/blob/master/template.html). Usage example:
|
|
377
456
|
|
|
378
457
|
```js
|
|
379
458
|
const MailTime = require('mail-time');
|
|
@@ -394,6 +473,8 @@ mailQueue.sendMail({
|
|
|
394
473
|
|
|
395
474
|
### Template Example
|
|
396
475
|
|
|
476
|
+
Pass custom template via `template` property to `.sendMail()` method
|
|
477
|
+
|
|
397
478
|
```js
|
|
398
479
|
mailQueue.sendMail({
|
|
399
480
|
to: 'user@gmail.com',
|
|
@@ -441,6 +522,10 @@ DEBUG="true" EMAIL_DOMAIN="example.com" MONGO_URL="mongodb://127.0.0.1:27017/met
|
|
|
441
522
|
|
|
442
523
|
## Support this project:
|
|
443
524
|
|
|
444
|
-
-
|
|
445
|
-
-
|
|
525
|
+
- Star on [GitHub](https://github.com/veliovgroup/mail-time)
|
|
526
|
+
- Star on [NPM](https://www.npmjs.com/package/mail-time)
|
|
527
|
+
- Star on [Atmosphere](https://atmospherejs.com/ostrio/mailer)
|
|
528
|
+
- [Sponsor maintainer via GitHub](https://github.com/sponsors/dr-dimitru) — support open source with one-time contribution or on a regular basis
|
|
529
|
+
- [Sponsor veliovgroup via GitHub](https://github.com/sponsors/veliovgroup) — support company behind this package
|
|
530
|
+
- [Support via PayPal](https://paypal.me/veliovgroup) — support our open source contributions
|
|
446
531
|
- Use [ostr.io](https://ostr.io) — [Monitoring](https://snmp-monitoring.com), [Analytics](https://ostr.io/info/web-analytics), [WebSec](https://domain-protection.info), [Web-CRON](https://web-cron.info) and [Pre-rendering](https://prerendering.com) for a website
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const JoSk
|
|
2
|
-
const
|
|
1
|
+
const JoSk = require('josk');
|
|
2
|
+
const noop = () => {};
|
|
3
3
|
const merge = require('deepmerge');
|
|
4
4
|
const _debug = (isDebug, ...args) => {
|
|
5
5
|
if (isDebug) {
|
|
@@ -142,9 +142,9 @@ module.exports = class MailTime {
|
|
|
142
142
|
return false;
|
|
143
143
|
})();
|
|
144
144
|
|
|
145
|
-
this.concatEmails
|
|
146
|
-
this.concatSubject
|
|
147
|
-
this.concatDelimiter
|
|
145
|
+
this.concatEmails = (opts.concatEmails !== true) ? false : true;
|
|
146
|
+
this.concatSubject = (opts.concatSubject && typeof opts.concatSubject === 'string') ? opts.concatSubject : 'Multiple notifications';
|
|
147
|
+
this.concatDelimiter = (opts.concatDelimiter && typeof opts.concatDelimiter === 'string') ? opts.concatDelimiter : '<hr>';
|
|
148
148
|
this.concatThrottling = ((opts.concatThrottling && !isNaN(opts.concatThrottling)) ? parseInt(opts.concatThrottling) : 60) * 1000;
|
|
149
149
|
|
|
150
150
|
if (this.concatThrottling < 2048) {
|
|
@@ -163,7 +163,7 @@ module.exports = class MailTime {
|
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
this.collection = opts.db.collection('__mailTimeQueue__' + this.prefix);
|
|
166
|
-
this.collection.createIndex({ to: 1, isSent: 1 }, (indexError) => {
|
|
166
|
+
this.collection.createIndex({ to: 1, isSent: 1, sendAt: 1 }, (indexError) => {
|
|
167
167
|
if (indexError) {
|
|
168
168
|
_logError('[createIndex]', indexError);
|
|
169
169
|
}
|
|
@@ -192,7 +192,7 @@ module.exports = class MailTime {
|
|
|
192
192
|
// mailOptions.Other nodeMailer `sendMail` options...
|
|
193
193
|
|
|
194
194
|
if (this.type === 'server') {
|
|
195
|
-
|
|
195
|
+
const scheduler = new JoSk({
|
|
196
196
|
db: opts.db,
|
|
197
197
|
debug: this.debug,
|
|
198
198
|
prefix: `mailTimeQueue${this.prefix}`,
|
|
@@ -202,7 +202,7 @@ module.exports = class MailTime {
|
|
|
202
202
|
maxRevolvingDelay: this.maxRevolvingDelay
|
|
203
203
|
});
|
|
204
204
|
|
|
205
|
-
|
|
205
|
+
scheduler.setInterval(this.___send.bind(this), this.revolvingInterval, `mailTimeQueue${this.prefix}`);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
@@ -272,14 +272,13 @@ module.exports = class MailTime {
|
|
|
272
272
|
return _mailOpts;
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
-
|
|
276
|
-
@memberOf MailTime
|
|
277
|
-
@name ___send
|
|
278
|
-
@param ready {Function} - See JoSk NPM package
|
|
279
|
-
@returns {void}
|
|
275
|
+
/**
|
|
276
|
+
* @memberOf MailTime
|
|
277
|
+
* @name ___send
|
|
278
|
+
* @param ready {Function} - See JoSk NPM package
|
|
279
|
+
* @returns {void}
|
|
280
280
|
*/
|
|
281
281
|
___send(ready) {
|
|
282
|
-
let finished = 0;
|
|
283
282
|
const cursor = this.collection.find({
|
|
284
283
|
isSent: false,
|
|
285
284
|
sendAt: {
|
|
@@ -299,113 +298,96 @@ module.exports = class MailTime {
|
|
|
299
298
|
}
|
|
300
299
|
});
|
|
301
300
|
|
|
302
|
-
cursor.
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
if (count === ++finished) {
|
|
323
|
-
ready();
|
|
301
|
+
cursor.forEach((task) => {
|
|
302
|
+
this.collection.updateOne({
|
|
303
|
+
_id: task._id
|
|
304
|
+
}, {
|
|
305
|
+
$set: {
|
|
306
|
+
isSent: true
|
|
307
|
+
},
|
|
308
|
+
$inc: {
|
|
309
|
+
tries: 1
|
|
310
|
+
}
|
|
311
|
+
}, (updateError) => {
|
|
312
|
+
if (updateError) {
|
|
313
|
+
this.___handleError(task, updateError, {});
|
|
314
|
+
} else {
|
|
315
|
+
let transport;
|
|
316
|
+
let transportIndex;
|
|
317
|
+
if (this.strategy === 'balancer') {
|
|
318
|
+
this.transport = this.transport + 1;
|
|
319
|
+
if (this.transport >= this.transports.length) {
|
|
320
|
+
this.transport = 0;
|
|
324
321
|
}
|
|
322
|
+
transportIndex = this.transport;
|
|
323
|
+
transport = this.transports[this.transport];
|
|
324
|
+
} else {
|
|
325
|
+
transportIndex = task.transport;
|
|
326
|
+
transport = this.transports[task.transport];
|
|
327
|
+
}
|
|
325
328
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if (
|
|
332
|
-
this.
|
|
333
|
-
|
|
334
|
-
this.transport = 0;
|
|
335
|
-
}
|
|
336
|
-
transportIndex = this.transport;
|
|
337
|
-
transport = this.transports[this.transport];
|
|
338
|
-
} else {
|
|
339
|
-
transportIndex = task.transport;
|
|
340
|
-
transport = this.transports[task.transport];
|
|
329
|
+
try {
|
|
330
|
+
const _mailOpts = this.___compileMailOpts(transport, task);
|
|
331
|
+
|
|
332
|
+
_debug(this.debug, '[sendMail] [sending] To:', _mailOpts.to);
|
|
333
|
+
transport.sendMail(_mailOpts, (error, info) => {
|
|
334
|
+
if (error) {
|
|
335
|
+
this.___handleError(task, error, info);
|
|
336
|
+
return;
|
|
341
337
|
}
|
|
342
338
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
this.___handleError(task, 'Message not accepted or Greeting never received', info);
|
|
355
|
-
return;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
_debug(this.debug, `email successfully sent, attempts: #${task.tries}, transport #${transportIndex} to: `, _mailOpts.to);
|
|
359
|
-
if (this.keepHistory) {
|
|
360
|
-
this.___triggerCallbacks(void 0, task, info);
|
|
361
|
-
} else {
|
|
362
|
-
this.collection.deleteOne({ _id: task._id }, () => {
|
|
363
|
-
this.___triggerCallbacks(void 0, task, info);
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return;
|
|
339
|
+
if (info.accepted && !info.accepted.length) {
|
|
340
|
+
this.___handleError(task, 'Message not accepted or Greeting never received', info);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
_debug(this.debug, `email successfully sent, attempts: #${task.tries}, transport #${transportIndex} to: `, _mailOpts.to);
|
|
345
|
+
if (this.keepHistory) {
|
|
346
|
+
this.___triggerCallbacks(void 0, task, info);
|
|
347
|
+
} else {
|
|
348
|
+
this.collection.deleteOne({ _id: task._id }, () => {
|
|
349
|
+
this.___triggerCallbacks(void 0, task, info);
|
|
368
350
|
});
|
|
369
|
-
} catch (e) {
|
|
370
|
-
_logError('Exception during runtime:', e);
|
|
371
|
-
this.___handleError(task, e, {});
|
|
372
351
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
352
|
+
|
|
353
|
+
return;
|
|
354
|
+
});
|
|
355
|
+
} catch (e) {
|
|
356
|
+
_logError('Exception during runtime:', e);
|
|
357
|
+
this.___handleError(task, e, {});
|
|
379
358
|
}
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
}, (forEachError) => {
|
|
362
|
+
ready();
|
|
363
|
+
cursor.close();
|
|
364
|
+
if (forEachError) {
|
|
365
|
+
_logError('[___send] [forEach] [forEachError]', forEachError);
|
|
384
366
|
}
|
|
385
367
|
});
|
|
386
368
|
}
|
|
387
369
|
|
|
388
|
-
|
|
389
|
-
@memberOf MailTime
|
|
390
|
-
@name send
|
|
391
|
-
@description alias of `sendMail`
|
|
392
|
-
@returns {void}
|
|
370
|
+
/**
|
|
371
|
+
* @memberOf MailTime
|
|
372
|
+
* @name send
|
|
373
|
+
* @description alias of `sendMail`
|
|
374
|
+
* @returns {void}
|
|
393
375
|
*/
|
|
394
376
|
send(opts, callback) {
|
|
395
377
|
this.sendMail(opts, callback);
|
|
396
378
|
}
|
|
397
379
|
|
|
398
|
-
|
|
399
|
-
@memberOf MailTime
|
|
400
|
-
@name sendMail
|
|
401
|
-
@param opts {Object} - Letter options with next properties:
|
|
402
|
-
@param opts.sendAt {Date} - When email should be sent
|
|
403
|
-
@param opts.template {String} - Template string
|
|
404
|
-
@param opts[key] {mix} - Other MailOptions according to NodeMailer lib documentation
|
|
405
|
-
@param callback {Function} - [OPTIONAL] Callback function
|
|
406
|
-
@returns {void}
|
|
380
|
+
/**
|
|
381
|
+
* @memberOf MailTime
|
|
382
|
+
* @name sendMail
|
|
383
|
+
* @param opts {Object} - Letter options with next properties:
|
|
384
|
+
* @param opts.sendAt {Date} - When email should be sent
|
|
385
|
+
* @param opts.template {String} - Template string
|
|
386
|
+
* @param opts[key] {mix} - Other MailOptions according to NodeMailer lib documentation
|
|
387
|
+
* @param callback {Function} - [OPTIONAL] Callback function
|
|
388
|
+
* @returns {void}
|
|
407
389
|
*/
|
|
408
|
-
sendMail(opts = {}, callback =
|
|
390
|
+
sendMail(opts = {}, callback = noop) {
|
|
409
391
|
_debug(this.debug, '[sendMail] [attempt] To:', opts.to);
|
|
410
392
|
if (!opts.html && !opts.text) {
|
|
411
393
|
throw new Error('`html` nor `text` field is presented, at least one of those fields is required');
|
|
@@ -423,8 +405,8 @@ module.exports = class MailTime {
|
|
|
423
405
|
opts.concatSubject = false;
|
|
424
406
|
}
|
|
425
407
|
|
|
426
|
-
let _sendAt
|
|
427
|
-
const _template
|
|
408
|
+
let _sendAt = opts.sendAt;
|
|
409
|
+
const _template = opts.template;
|
|
428
410
|
const _concatSubject = opts.concatSubject;
|
|
429
411
|
delete opts.sendAt;
|
|
430
412
|
delete opts.template;
|
|
@@ -437,7 +419,10 @@ module.exports = class MailTime {
|
|
|
437
419
|
if (this.concatEmails) {
|
|
438
420
|
this.collection.findOne({
|
|
439
421
|
to: opts.to,
|
|
440
|
-
isSent: false
|
|
422
|
+
isSent: false,
|
|
423
|
+
sendAt: {
|
|
424
|
+
$lte: new Date(+_sendAt + this.concatThrottling)
|
|
425
|
+
}
|
|
441
426
|
}, {
|
|
442
427
|
projection: {
|
|
443
428
|
_id: 1,
|
|
@@ -500,13 +485,13 @@ module.exports = class MailTime {
|
|
|
500
485
|
return;
|
|
501
486
|
}
|
|
502
487
|
|
|
503
|
-
|
|
504
|
-
@memberOf MailTime
|
|
505
|
-
@name ___handleError
|
|
506
|
-
@param task {Object} - Email task record form Mongo
|
|
507
|
-
@param error {mix} - Error String/Object/Error
|
|
508
|
-
@param info {Object} - Info object returned from nodemailer
|
|
509
|
-
@returns {void}
|
|
488
|
+
/**
|
|
489
|
+
* @memberOf MailTime
|
|
490
|
+
* @name ___handleError
|
|
491
|
+
* @param task {Object} - Email task record form Mongo
|
|
492
|
+
* @param error {mix} - Error String/Object/Error
|
|
493
|
+
* @param info {Object} - Info object returned from nodemailer
|
|
494
|
+
* @returns {void}
|
|
510
495
|
*/
|
|
511
496
|
___handleError(task, error, info) {
|
|
512
497
|
if (!task) {
|
|
@@ -544,16 +529,16 @@ module.exports = class MailTime {
|
|
|
544
529
|
}
|
|
545
530
|
}
|
|
546
531
|
|
|
547
|
-
|
|
548
|
-
@memberOf MailTime
|
|
549
|
-
@name ___addToQueue
|
|
550
|
-
@param opts {Object} - Letter options with next properties:
|
|
551
|
-
@param opts.sendAt {Date} - When email should be sent
|
|
552
|
-
@param opts.template {String} - Email template
|
|
553
|
-
@param opts.mailOptions {Object} - MailOptions according to NodeMailer lib
|
|
554
|
-
@param opts.concatSubject {String} - Email subject used when sending multiple concatenated emails
|
|
555
|
-
@param callback {Function} - [OPTIONAL] Callback function
|
|
556
|
-
@returns {void}
|
|
532
|
+
/**
|
|
533
|
+
* @memberOf MailTime
|
|
534
|
+
* @name ___addToQueue
|
|
535
|
+
* @param opts {Object} - Letter options with next properties:
|
|
536
|
+
* @param opts.sendAt {Date} - When email should be sent
|
|
537
|
+
* @param opts.template {String} - Email template
|
|
538
|
+
* @param opts.mailOptions {Object} - MailOptions according to NodeMailer lib
|
|
539
|
+
* @param opts.concatSubject {String} - Email subject used when sending multiple concatenated emails
|
|
540
|
+
* @param callback {Function} - [OPTIONAL] Callback function
|
|
541
|
+
* @returns {void}
|
|
557
542
|
*/
|
|
558
543
|
___addToQueue(opts, callback) {
|
|
559
544
|
_debug(this.debug, '[sendMail] [adding to queue] To:', opts.mailOptions.to);
|
|
@@ -587,16 +572,16 @@ module.exports = class MailTime {
|
|
|
587
572
|
});
|
|
588
573
|
}
|
|
589
574
|
|
|
590
|
-
|
|
591
|
-
@memberOf MailTime
|
|
592
|
-
@name ___render
|
|
593
|
-
@param string {String} - Template with Spacebars/Blaze/Mustache-like placeholders
|
|
594
|
-
@param replacements {Object} - Blaze/Mustache-like helpers Object
|
|
595
|
-
@returns {String}
|
|
575
|
+
/**
|
|
576
|
+
* @memberOf MailTime
|
|
577
|
+
* @name ___render
|
|
578
|
+
* @param string {String} - Template with Spacebars/Blaze/Mustache-like placeholders
|
|
579
|
+
* @param replacements {Object} - Blaze/Mustache-like helpers Object
|
|
580
|
+
* @returns {String}
|
|
596
581
|
*/
|
|
597
582
|
___render(_string, replacements) {
|
|
598
583
|
let i;
|
|
599
|
-
let string
|
|
584
|
+
let string = _string;
|
|
600
585
|
const matchHTML = string.match(/\{{3}\s?([a-zA-Z0-9\-\_]+)\s?\}{3}/g);
|
|
601
586
|
if (matchHTML) {
|
|
602
587
|
for (i = 0; i < matchHTML.length; i++) {
|
|
@@ -617,13 +602,13 @@ module.exports = class MailTime {
|
|
|
617
602
|
return string;
|
|
618
603
|
}
|
|
619
604
|
|
|
620
|
-
|
|
621
|
-
@memberOf MailTime
|
|
622
|
-
@name ___triggerCallbacks
|
|
623
|
-
@param error {mix} - Error thrown during sending email
|
|
624
|
-
@param task {Object} - Task record from mongodb
|
|
625
|
-
@param info {Object} - Info object returned from NodeMailer's `sendMail` method
|
|
626
|
-
@returns {void 0}
|
|
605
|
+
/**
|
|
606
|
+
* @memberOf MailTime
|
|
607
|
+
* @name ___triggerCallbacks
|
|
608
|
+
* @param error {mix} - Error thrown during sending email
|
|
609
|
+
* @param task {Object} - Task record from mongodb
|
|
610
|
+
* @param info {Object} - Info object returned from NodeMailer's `sendMail` method
|
|
611
|
+
* @returns {void 0}
|
|
627
612
|
*/
|
|
628
613
|
___triggerCallbacks(error, task, info) {
|
|
629
614
|
const _id = task._id.toHexString();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mail-time",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Bulletproof email queue on top of NodeMailer
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Bulletproof email queue on top of NodeMailer for a single and multi-server setups",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "mocha ./test/npm.js"
|
|
@@ -49,15 +49,15 @@
|
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"deepmerge": "^4.2.2",
|
|
52
|
-
"josk": "^
|
|
52
|
+
"josk": "^3.0.0"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"bson": "^4.
|
|
56
|
-
"bson-ext": "^
|
|
57
|
-
"chai": "^4.3.
|
|
58
|
-
"mocha": "^
|
|
59
|
-
"mongodb": "^
|
|
60
|
-
"nodemailer": "^6.
|
|
61
|
-
"nodemailer-direct-transport": "^3.
|
|
55
|
+
"bson": "^4.6.4",
|
|
56
|
+
"bson-ext": "^4.0.2",
|
|
57
|
+
"chai": "^4.3.6",
|
|
58
|
+
"mocha": "^10.0.0",
|
|
59
|
+
"mongodb": "^4.6.0",
|
|
60
|
+
"nodemailer": "^6.7.5",
|
|
61
|
+
"nodemailer-direct-transport": "^3.0.7"
|
|
62
62
|
}
|
|
63
63
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
For full changelog see [releases](https://github.com/veliovgroup/Mail-Time/releases) in GitHub
|
package/HISTORY.md
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
For full history see [releases](https://github.com/veliovgroup/Mail-Time/releases) in GitHub
|