email-bounce-parser 1.0.19 → 1.0.21
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/lib/parser.js +69 -83
- package/package.json +2 -2
package/lib/parser.js
CHANGED
|
@@ -35,11 +35,13 @@ var ERROR_CODES_TYPES = {
|
|
|
35
35
|
"550 5.1.1" : "no_such_recipient",
|
|
36
36
|
"550 5.2.1" : "recipient_disabled_or_recipient_rate_limited",
|
|
37
37
|
"550 5.7.1" : "spam_content",
|
|
38
|
+
"550 5.7.26" : "authentication_failure",
|
|
38
39
|
"551" : "user_not_local",
|
|
39
40
|
"552" : "action_aborted_exceeded_storage_allocation",
|
|
40
41
|
"552 5.2.2" : "mailbox_over_quota",
|
|
41
42
|
"552 5.2.3" : "message_size_limit",
|
|
42
43
|
"553" : "action_not_taken_mailbox_name_not_allowed",
|
|
44
|
+
"553 5.1.2" : "no_such_recipient",
|
|
43
45
|
"554" : "transaction_failed",
|
|
44
46
|
"554 5.7.1" : "spam_content",
|
|
45
47
|
"555" : "parameters_not_recognized",
|
|
@@ -78,19 +80,20 @@ var REGEXES = {
|
|
|
78
80
|
/Message rejected by\:\s+([\S\.]+?)$/m, // Outlook error
|
|
79
81
|
/from (\S+) \[([\d\.]+)\](?:\:(\d+)\:)?/m,
|
|
80
82
|
/conversation with (\S+)\[([\d\.]+)\](?:\:(\d+)\:)? timed out/m,
|
|
83
|
+
/lost connection with (\S+)\[([\d\.]+)\](?:\:(\d+)\:)?/m, // "lost connection with mx.mail-data.net[134.244.220.69]"
|
|
81
84
|
/Generating server: (\S+)(?:\[([\d\.]+)\])?(?:\:(\d+)\:)?/m // "Generating server: PH7PR02MB9549495.namprd02.prod.outlook.com"
|
|
82
85
|
],
|
|
83
86
|
|
|
84
87
|
error : [
|
|
85
|
-
/said\: (\d{3}(?:[\s
|
|
86
|
-
/said\: (\d{3}(?:[\s
|
|
88
|
+
/said\: (\d{3}(?:[\s\-\#\']{1,2}\d\.\d\.\d{1,3})?) (.+) \(in reply to/,
|
|
89
|
+
/said\: (\d{3}(?:[\s\-\#\']{1,2}\d\.\d\.\d{1,3})?)-(.+)/,
|
|
87
90
|
/(\d{3}\-\'\d\.\d\.\d{1,3}) (.+)/,
|
|
88
|
-
/LMTP error after .+?\:\<.+?\>\: (\d{3}(?:[\s
|
|
89
|
-
/remote server returned \'(\d{3}(?:[\s
|
|
90
|
-
/The response from the remote server was:\s(\d{3}(?:[\s
|
|
91
|
-
/refused to talk to me\: (\d{3}(?:[\s
|
|
92
|
-
/(?:error|reason)\:\s*?(\d{3}(?:[\s
|
|
93
|
-
/(\d{3}[\s
|
|
91
|
+
/LMTP error after .+?\:\<.+?\>\: (\d{3}(?:[\s\-\#\']{1,2}\d\.\d\.\d{1,3})?) <.+?\>(.+)$/m,
|
|
92
|
+
/remote server returned \'(\d{3}(?:[\s\-\#\']{1,2}\d\.\d\.\d{1,3})?) (.+)\'/i,
|
|
93
|
+
/The response from the remote server was:\s(\d{3}(?:[\s\-\#\']{1,2}\d\.\d\.\d{1,3})?) (.+)/,
|
|
94
|
+
/refused to talk to me\: (\d{3}(?:[\s\-\#\']{1,2}\d\.\d\.\d{1,3})?) (.+)/,
|
|
95
|
+
/(?:error|reason)\:\s*?(\d{3}(?:[\s\-\#\']{1,2}\d\.\d\.\d{1,3})?) (.+)/i,
|
|
96
|
+
/(\d{3}[\s\-\#\']{1,2}\d\.\d\.\d{1,3})/,
|
|
94
97
|
/(\d{3}\-\'\d\.\d\.\d{1,3})/
|
|
95
98
|
],
|
|
96
99
|
|
|
@@ -122,39 +125,41 @@ var REGEXES = {
|
|
|
122
125
|
],
|
|
123
126
|
|
|
124
127
|
temporary_safe : /(temporary|temporarily)/i,
|
|
125
|
-
blocked : /((?:is listed)|blocked|banned|denied|dnsbl)/i,
|
|
126
|
-
spam : /(spam)/i,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
128
|
+
blocked : /((?:is listed)|blocked|block list|banned|denied|dnsbl)/i,
|
|
129
|
+
spam : /(spam|unsolicited)/i,
|
|
130
|
+
|
|
131
|
+
enhanced_types : {
|
|
132
|
+
no_such_recipient : [
|
|
133
|
+
/(recipient address rejected: access denied)/i, // Outlook DBEB for invalid addresses
|
|
134
|
+
/(no such (?:account|user|mailbox|recipient))/i,
|
|
135
|
+
/((?:terminated|disabled|inactive|not found|unavailable|invalid) (?:account|user|mailbox|recipient))/i,
|
|
136
|
+
/(do(e)?sn\'t exist)/i, // Some Chinese SMTP return "dosn't" instead of "doesn't"
|
|
137
|
+
/(user (?:.+?) does not exist)/i,
|
|
138
|
+
/((?:account|user|mailbox|recipient) (?:.+@.+ )?(?:is )?(?:terminated|disabled|inactive|not found|unavailable|invalid|rejected))/i
|
|
139
|
+
],
|
|
140
|
+
|
|
141
|
+
server_unknown : [
|
|
142
|
+
/(does not accept mail)/i,
|
|
143
|
+
/(domain (?:name\s+)?(?:\S+\s)?(?:not found|does not exist))/i, // "domain does not exist" or "domain name does not exist" or "domain acme.com does not exist" or "domain name acme.com does not exist"
|
|
144
|
+
/(no route to host)/i
|
|
145
|
+
],
|
|
146
|
+
|
|
147
|
+
server_timeout : [
|
|
148
|
+
/(timeout|timed[\s\-]out)/i
|
|
149
|
+
],
|
|
150
|
+
|
|
151
|
+
mailbox_full : [
|
|
152
|
+
/(out of storage|(?:mailbox (?:is )?full)|(?:user (?:is )?over quota))/i // "user is over quota" (iCloud)
|
|
153
|
+
],
|
|
154
|
+
|
|
155
|
+
reputation : [
|
|
156
|
+
/(rate limited due to IP reputation)/i,
|
|
157
|
+
/(new or untrusted IP)/i
|
|
158
|
+
]
|
|
159
|
+
},
|
|
154
160
|
|
|
155
161
|
error_code : [
|
|
156
|
-
/(\d{3})[\s
|
|
157
|
-
/(\d{3})\-\'(\d\.\d\.\d{1,3})/, // "550-'5.4.1" or "550-'5.4.11" or "550-'5.4.110"
|
|
162
|
+
/(\d{3})[\s\-\#\']{1,2}(\d\.\d\.\d{1,3})/, // "550 5.4.1" or "550 #5.4.1" or "550-5.4.1" or "550-'5.4.1"
|
|
158
163
|
/(\d{3})/ // "550"
|
|
159
164
|
]
|
|
160
165
|
};
|
|
@@ -169,9 +174,7 @@ class Parser {
|
|
|
169
174
|
* Constructor
|
|
170
175
|
*/
|
|
171
176
|
constructor() {
|
|
172
|
-
this.__regexes =
|
|
173
|
-
|
|
174
|
-
this.__initRegexes();
|
|
177
|
+
this.__regexes = this.__initRegexes(REGEXES);
|
|
175
178
|
}
|
|
176
179
|
|
|
177
180
|
|
|
@@ -248,30 +251,31 @@ class Parser {
|
|
|
248
251
|
/**
|
|
249
252
|
* Initializes regexes
|
|
250
253
|
* @private
|
|
251
|
-
* @
|
|
254
|
+
* @param {object} obj
|
|
255
|
+
* @return {object} Regexes
|
|
252
256
|
*/
|
|
253
|
-
__initRegexes() {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
+
__initRegexes(obj) {
|
|
258
|
+
var _regexes = {};
|
|
259
|
+
|
|
260
|
+
for (var _key in obj) {
|
|
261
|
+
var _entry = obj[_key];
|
|
257
262
|
|
|
258
263
|
if (Array.isArray(_entry)) {
|
|
259
|
-
|
|
260
|
-
this.__regexes[_key_line] = [];
|
|
264
|
+
_regexes[_key] = [];
|
|
261
265
|
|
|
262
266
|
for (var _i = 0; _i < _entry.length; _i++) {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
this.__regexes[_key].push(
|
|
266
|
-
new RE2(_regex)
|
|
267
|
+
_regexes[_key].push(
|
|
268
|
+
new RE2(_entry[_i])
|
|
267
269
|
);
|
|
268
270
|
}
|
|
271
|
+
} else if (typeof _entry === "object" && Object.keys(_entry).length > 0) {
|
|
272
|
+
_regexes[_key] = this.__initRegexes(_entry);
|
|
269
273
|
} else {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
this.__regexes[_key] = new RE2(_regex);
|
|
274
|
+
_regexes[_key] = new RE2(_entry);
|
|
273
275
|
}
|
|
274
276
|
}
|
|
277
|
+
|
|
278
|
+
return _regexes;
|
|
275
279
|
}
|
|
276
280
|
|
|
277
281
|
|
|
@@ -391,40 +395,22 @@ class Parser {
|
|
|
391
395
|
_spam = false;
|
|
392
396
|
|
|
393
397
|
// Detect enhanced-type from bounce content
|
|
394
|
-
var
|
|
398
|
+
for (var _key in this.__regexes.enhanced_types) {
|
|
399
|
+
var _match = loopRegexes(
|
|
400
|
+
this.__regexes.enhanced_types[_key],
|
|
395
401
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
}
|
|
402
|
+
str
|
|
403
|
+
);
|
|
399
404
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
_type = "server_unknown";
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
_match = loopRegexes(this.__regexes.enhanced_types_server_timeout, str);
|
|
407
|
-
|
|
408
|
-
if (!_type && _match && _match.length > 1) {
|
|
409
|
-
_type = "server_timeout";
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
_match = loopRegexes(this.__regexes.enhanced_types_mailbox_full, str);
|
|
413
|
-
|
|
414
|
-
if (!_type && _match && _match.length > 1) {
|
|
415
|
-
_type = "mailbox_full";
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
_match = loopRegexes(this.__regexes.enhanced_types_reputation, str);
|
|
419
|
-
|
|
420
|
-
if (!_type && _match && _match.length > 1) {
|
|
421
|
-
_type = "reputation";
|
|
405
|
+
if (!_type && _match && _match.length > 1) {
|
|
406
|
+
_type = _key;
|
|
407
|
+
}
|
|
422
408
|
}
|
|
423
409
|
|
|
424
410
|
// Detect enhanced-type from enhanced error code
|
|
425
411
|
// Notice: this is done as a last resort, as sometimes enhanced code \
|
|
426
412
|
// doesn't clearly convey the actual error
|
|
427
|
-
if (!_type &&
|
|
413
|
+
if (!_type && code.enhanced) {
|
|
428
414
|
_type = ERROR_CODES_TYPES[`${code.basic} ${code.enhanced}`] || null;
|
|
429
415
|
}
|
|
430
416
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "email-bounce-parser",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"description": "Parses bounce emails and extract errors",
|
|
5
5
|
"author": "Eliott Vincent <eliott@crisp.chat>",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"nodeunit-x": "0.15.0"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"re2": "1.20.
|
|
26
|
+
"re2": "1.20.7"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
29
29
|
"parser",
|