email-bounce-parser 1.0.16 → 1.0.18

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/README.md CHANGED
@@ -39,7 +39,7 @@ console.log(result);
39
39
  ### Parse a bounce email
40
40
 
41
41
  `read(body)` parses the bounce email and extracts available information (error code and type, server, original recipient, etc.):
42
- * `body` must be a string representing the bounce email body (as returned by [mailparser](https://github.com/nodemailer/mailparser), for example)
42
+ * `body` must be a string representing the bounce email **text** body (not HTML body). You can use [mailparser](https://github.com/nodemailer/mailparser) for example.
43
43
 
44
44
  ```js
45
45
  const EmailBounceParse = require("email-bounce-parser");
@@ -53,7 +53,7 @@ console.log(result);
53
53
  // email: {
54
54
  // body: "This is the mail system at host mailer.acme.email [...] (in reply to RCPT TO command)",
55
55
  // intro: "This is the mail system at host mailer.acme.email [...] The mail system",
56
- // error: "<support@yipee.com>: host smtp.secureserver.net[92.240.81.0] said: [...] (in reply to RCPT TO command)"
56
+ // error: "<john@yipee.com>: host smtp.secureserver.net[92.240.81.0] said: [...] (in reply to RCPT TO command)"
57
57
  // },
58
58
  //
59
59
  // data: {
@@ -62,7 +62,7 @@ console.log(result);
62
62
  // basic: "550",
63
63
  // enhanced: "5.1.1"
64
64
  // },
65
- // label: "<support@yipee.com> Recipient not found.",
65
+ // label: "<john@yipee.com> Recipient not found.",
66
66
  //
67
67
  // type: "action_not_taken",
68
68
  //
@@ -76,6 +76,8 @@ console.log(result);
76
76
  // }
77
77
  // },
78
78
  //
79
+ // recipient: "john@yipee.com",
80
+ //
79
81
  // server: {
80
82
  // hostname: "smtp.secureserver.net",
81
83
  // ip: "92.240.81.0",
package/lib/parser.js CHANGED
@@ -65,8 +65,8 @@ var REGEXES = {
65
65
  /\(in reply to end of ([A-Z\s]+) command\)$/m, // "in reply to end of DATA command"
66
66
  /\(in reply to ([A-Z\s]+) command\)$/m, // "in reply to RCPT TO command"
67
67
  /timed out while sending ([A-Z\s]+)$/m, // "timed out while sending (RCPT TO)", "timed out while sending RCPT TO"
68
- /error after ([A-Z\s]+)/m, // "LMTP error after RCPT TO"
69
- /while sending end of ([a-z\s]+)/m // "while sending end of data"
68
+ /error after ([A-Z\s]+)/i, // "LMTP error after RCPT TO"
69
+ /while sending end of ([a-z\s]+)/i // "while sending end of data"
70
70
  ],
71
71
 
72
72
  email_server : [
@@ -82,21 +82,30 @@ var REGEXES = {
82
82
  ],
83
83
 
84
84
  error : [
85
- /said\: (\d{3}(?:[\s\-]\d\.\d\.\d\d?)?) (.+) \(in reply to/,
86
- /said\: (\d{3}(?:[\s\-]\d\.\d\.\d\d?)?)-(.+)/,
87
- /(\d{3}\-\'\d\.\d\.\d\d?) (.+)/,
88
- /LMTP error after .+?\:\<.+?\>\: (\d{3}(?:[\s\-]\d\.\d\.\d\d?)?) <.+?\>(.+)$/m,
89
- /remote server returned \'(\d{3}(?:[\s\-]\d\.\d\.\d\d?)?) (.+)\'/i,
90
- /The response from the remote server was:\s(\d{3}(?:[\s\-]\d\.\d\.\d\d?)?) (.+)/,
91
- /refused to talk to me\: (\d{3}(?:[\s\-]\d\.\d\.\d\d?)?) (.+)/,
92
- /(?:error|reason)\:\s*?(\d{3}(?:[\s\-]\d\.\d\.\d\d?)?) (.+)/i,
93
- /(\d{3}[\s\-]\d\.\d\.\d\d?)/,
94
- /(\d{3}\-\'\d\.\d\.\d\d?)/
85
+ /said\: (\d{3}(?:[\s\-]\d\.\d\.\d{1,3})?) (.+) \(in reply to/,
86
+ /said\: (\d{3}(?:[\s\-]\d\.\d\.\d{1,3})?)-(.+)/,
87
+ /(\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})/,
94
+ /(\d{3}\-\'\d\.\d\.\d{1,3})/
95
95
  ],
96
96
 
97
97
  error_lax : [
98
98
  /^(?:\<.+?\> \(expanded from \<.+?\>\)\:)(.+)/m, // "<john@acme.com> (expanded from <john@digiflex.com>): Domain name not found"
99
- /^(?:\<.+?\>\:)(.+)/m // "<john@acme.com>: Domain name not found"
99
+ /^(?:\<.+?\>\:)(.+)/m, // "<john@acme.com>: Domain name not found"
100
+ ],
101
+
102
+ error_label_cleanup_recipient : [
103
+ /^\<.+?\> \(expanded from \<.+?\>\)\:/m, // "<john@acme.com> (expanded from <john@digiflex.com>): Domain name not found"
104
+ /^\<.+?\>\:/m, // "<john@acme.com>: Domain name not found"
105
+ ],
106
+
107
+ error_label_cleanup_command : [
108
+ /\(in reply to (?:end of)?[A-Z\s]+ command\)$/m // "in reply to DATA command" or "in reply to end of DATA command"
100
109
  ],
101
110
 
102
111
  recipient : [
@@ -104,7 +113,7 @@ var REGEXES = {
104
113
  /the following message to \<(.+?)\> was undeliverable/i,
105
114
  /to the following addresses:\s*(.+)/i,
106
115
  /^\<(.+?)\>:/m,
107
- /^(.+?)\s?\n?\s*[\[|<]mailto\:(.+?)[\]|>]/mi, // "john@acme.com<mailto:john@acme.com>"
116
+ /^(.+?)\s?(?:\s\(.*?\))?\n?\s*[\[|<]mailto\:(.+?)[\]|>]/mi, // "john@acme.com<mailto:john@acme.com>" or "john@acme.com[mailto:john@acme.com]" or "john@acme.com (john@acme.com)<mailto:john@acme.com>"
108
117
  /^your message wasn't delivered to (.+?)\s/mi, // "Your message wasn't delivered to john@acme.com"
109
118
  /^your message to (.+?) couldn\'t/mi, // "Your message to john@acme.com couldn't"
110
119
  /\<(.+?)\> \(expanded from \<.+?\>\)\:/, // "<john@acme.com> (expanded from <john@digiflex.com>): "
@@ -126,7 +135,8 @@ var REGEXES = {
126
135
 
127
136
  enhanced_types_server_unknown : [
128
137
  /(does not accept mail)/i,
129
- /(domain name not found)/i
138
+ /(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"
139
+ /(no route to host)/i
130
140
  ],
131
141
 
132
142
  enhanced_types_server_timeout : [
@@ -138,8 +148,8 @@ var REGEXES = {
138
148
  ],
139
149
 
140
150
  error_code : [
141
- /(\d{3})[\s\-](\d\.\d\.\d\d?)/, // "550 5.4.1" or "550-5.4.1" or "550-5.4.11"
142
- /(\d{3})\-\'(\d\.\d\.\d\d?)/, // "550-'5.4.1" or "550-'5.4.11"
151
+ /(\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"
152
+ /(\d{3})\-\'(\d\.\d\.\d{1,3})/, // "550-'5.4.1" or "550-'5.4.11" or "550-'5.4.110"
143
153
  /(\d{3})/ // "550"
144
154
  ]
145
155
  };
@@ -567,6 +577,13 @@ class Parser {
567
577
 
568
578
  _label = trimString(_label);
569
579
 
580
+ // Strip recipient (at the beginning) and command (at the end), in case \
581
+ // they are still present
582
+ _label = loopRegexes(this.__regexes.error_label_cleanup_recipient, _label, "replace");
583
+ _label = loopRegexes(this.__regexes.error_label_cleanup_command, _label, "replace");
584
+
585
+ _label = trimString(_label);
586
+
570
587
  return _label;
571
588
  }
572
589
 
package/lib/utils.js CHANGED
@@ -23,6 +23,8 @@ var loopRegexes = function(
23
23
  regexes, str, mode = "match", highestPosition = true
24
24
  ) {
25
25
  var _match;
26
+ var _minLength = mode === "split" ? 1 : 0;
27
+ var _maxLength = str.length;
26
28
 
27
29
  for (var _i = 0; _i < regexes.length; _i++) {
28
30
  var _regex = regexes[_i];
@@ -40,15 +42,12 @@ var loopRegexes = function(
40
42
  _match = _currentMatch;
41
43
 
42
44
  // A successfull replace must return a smaller string than the input
43
- var _maxLength = str.length;
44
-
45
45
  if (_match.length < _maxLength) {
46
46
  break;
47
47
  }
48
48
  } else if (mode === "split" || mode === "match") {
49
- // A successfull split must return an array with at least two items
50
- var _minLength = mode === "split" ? 1 : 0;
51
49
 
50
+ // A successfull split must return an array with at least two items
52
51
  if ((_currentMatch || []).length > _minLength) {
53
52
  if (highestPosition === true) {
54
53
  // No previous match?
@@ -80,7 +79,7 @@ var loopRegexes = function(
80
79
  }
81
80
  }
82
81
 
83
- return (_match || []);
82
+ return (mode === "replace") ? (_match || "") : (_match || []);
84
83
  }
85
84
 
86
85
 
@@ -91,7 +90,7 @@ var loopRegexes = function(
91
90
  * @return {string} The trimed string
92
91
  */
93
92
  var trimString = function(str) {
94
- return ((str || "").trim() || null)
93
+ return ((str || "").trim() || "");
95
94
  }
96
95
 
97
96
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "email-bounce-parser",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Parses bounce emails and extract errors",
5
5
  "author": "Eliott Vincent <eliott@crisp.chat>",
6
6
  "main": "lib/index.js",