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 +5 -3
- package/lib/parser.js +34 -17
- package/lib/utils.js +5 -6
- package/package.json +1 -1
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 (
|
|
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: "<
|
|
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: "<
|
|
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]+)/
|
|
69
|
-
/while sending end of ([a-z\s]+)/
|
|
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
|
|
86
|
-
/said\: (\d{3}(?:[\s\-]\d\.\d\.\d
|
|
87
|
-
/(\d{3}\-\'\d\.\d\.\d
|
|
88
|
-
/LMTP error after .+?\:\<.+?\>\: (\d{3}(?:[\s\-]\d\.\d\.\d
|
|
89
|
-
/remote server returned \'(\d{3}(?:[\s\-]\d\.\d\.\d
|
|
90
|
-
/The response from the remote server was:\s(\d{3}(?:[\s\-]\d\.\d\.\d
|
|
91
|
-
/refused to talk to me\: (\d{3}(?:[\s\-]\d\.\d\.\d
|
|
92
|
-
/(?:error|reason)\:\s*?(\d{3}(?:[\s\-]\d\.\d\.\d
|
|
93
|
-
/(\d{3}[\s\-]\d\.\d\.\d
|
|
94
|
-
/(\d{3}\-\'\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
|
|
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
|
|
142
|
-
/(\d{3})\-\'(\d\.\d\.\d
|
|
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() ||
|
|
93
|
+
return ((str || "").trim() || "");
|
|
95
94
|
}
|
|
96
95
|
|
|
97
96
|
|