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.
Files changed (2) hide show
  1. package/lib/parser.js +69 -83
  2. 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\-]\d\.\d\.\d{1,3})?) (.+) \(in reply to/,
86
- /said\: (\d{3}(?:[\s\-]\d\.\d\.\d{1,3})?)-(.+)/,
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\-]\d\.\d\.\d{1,3})?) <.+?\>(.+)$/m,
89
- /remote server returned \'(\d{3}(?:[\s\-]\d\.\d\.\d{1,3})?) (.+)\'/i,
90
- /The response from the remote server was:\s(\d{3}(?:[\s\-]\d\.\d\.\d{1,3})?) (.+)/,
91
- /refused to talk to me\: (\d{3}(?:[\s\-]\d\.\d\.\d{1,3})?) (.+)/,
92
- /(?:error|reason)\:\s*?(\d{3}(?:[\s\-]\d\.\d\.\d{1,3})?) (.+)/i,
93
- /(\d{3}[\s\-]\d\.\d\.\d{1,3})/,
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
- enhanced_types_no_such_recipient : [
129
- /(recipient address rejected: access denied)/i, // Outlook DBEB for invalid addresses
130
- /(no such (?:account|user|mailbox|recipient))/i,
131
- /((?:terminated|disabled|inactive|not found|unavailable|invalid) (?:account|user|mailbox|recipient))/i,
132
- /(do(e)?sn\'t exist)/i, // Some Chinese SMTP return "dosn't" instead of "doesn't"
133
- /(user (?:.+?) does not exist)/i,
134
- /((?:account|user|mailbox|recipient) (?:.+@.+ )?(?:is )?(?:terminated|disabled|inactive|not found|unavailable|invalid))/i
135
- ],
136
-
137
- enhanced_types_server_unknown : [
138
- /(does not accept mail)/i,
139
- /(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"
140
- /(no route to host)/i
141
- ],
142
-
143
- enhanced_types_server_timeout : [
144
- /(timeout|timed[\s\-]out)/i
145
- ],
146
-
147
- enhanced_types_mailbox_full : [
148
- /(out of storage|(?:mailbox (?:is )?full)|(?:user (?:is )?over quota))/i // "user is over quota" (iCloud)
149
- ],
150
-
151
- enhanced_types_reputation : [
152
- /(rate limited due to IP reputation)/i
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\-](\d\.\d\.\d{1,3})/, // "550 5.4.1" or "550-5.4.1" or "550-5.4.11" or "550-5.4.110"
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
- * @return {undefined}
254
+ * @param {object} obj
255
+ * @return {object} Regexes
252
256
  */
253
- __initRegexes() {
254
- for (var _key in REGEXES) {
255
- var _key_line = `${_key}_line`;
256
- var _entry = REGEXES[_key];
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
- this.__regexes[_key] = [];
260
- this.__regexes[_key_line] = [];
264
+ _regexes[_key] = [];
261
265
 
262
266
  for (var _i = 0; _i < _entry.length; _i++) {
263
- var _regex = _entry[_i];
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
- var _regex = _entry;
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 _match = loopRegexes(this.__regexes.enhanced_types_no_such_recipient, str);
398
+ for (var _key in this.__regexes.enhanced_types) {
399
+ var _match = loopRegexes(
400
+ this.__regexes.enhanced_types[_key],
395
401
 
396
- if (_match && _match.length > 1) {
397
- _type = "no_such_recipient";
398
- }
402
+ str
403
+ );
399
404
 
400
- _match = loopRegexes(this.__regexes.enhanced_types_server_unknown, str);
401
-
402
- if (!_type && _match && _match.length > 1) {
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 && _match && code.enhanced) {
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.19",
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.1"
26
+ "re2": "1.20.7"
27
27
  },
28
28
  "keywords": [
29
29
  "parser",