Skip to content

Commit

Permalink
Improve enhanced type detection
Browse files Browse the repository at this point in the history
  • Loading branch information
eliottvincent committed Dec 9, 2023
1 parent beea8a2 commit f440a88
Showing 1 changed file with 53 additions and 70 deletions.
123 changes: 53 additions & 70 deletions lib/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,32 +125,34 @@ var REGEXES = {
blocked : /((?:is listed)|blocked|banned|denied|dnsbl)/i,
spam : /(spam)/i,

enhanced_types_no_such_recipient : [
/(recipient address rejected: access denied)/i, // Outlook DBEB for invalid addresses
/(no such (?:account|user|mailbox|recipient))/i,
/((?:terminated|disabled|inactive|not found|unavailable|invalid) (?:account|user|mailbox|recipient))/i,
/(do(e)?sn\'t exist)/i, // Some Chinese SMTP return "dosn't" instead of "doesn't"
/(user (?:.+?) does not exist)/i,
/((?:account|user|mailbox|recipient) (?:.+@.+ )?(?:is )?(?:terminated|disabled|inactive|not found|unavailable|invalid))/i
],

enhanced_types_server_unknown : [
/(does not accept mail)/i,
/(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"
/(no route to host)/i
],

enhanced_types_server_timeout : [
/(timeout|timed[\s\-]out)/i
],

enhanced_types_mailbox_full : [
/(out of storage|(?:mailbox (?:is )?full)|(?:user (?:is )?over quota))/i // "user is over quota" (iCloud)
],

enhanced_types_reputation : [
/(rate limited due to IP reputation)/i
],
enhanced_types : {
no_such_recipient : [
/(recipient address rejected: access denied)/i, // Outlook DBEB for invalid addresses
/(no such (?:account|user|mailbox|recipient))/i,
/((?:terminated|disabled|inactive|not found|unavailable|invalid) (?:account|user|mailbox|recipient))/i,
/(do(e)?sn\'t exist)/i, // Some Chinese SMTP return "dosn't" instead of "doesn't"
/(user (?:.+?) does not exist)/i,
/((?:account|user|mailbox|recipient) (?:.+@.+ )?(?:is )?(?:terminated|disabled|inactive|not found|unavailable|invalid|rejected))/i
],

server_unknown : [
/(does not accept mail)/i,
/(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"
/(no route to host)/i
],

server_timeout : [
/(timeout|timed[\s\-]out)/i
],

mailbox_full : [
/(out of storage|(?:mailbox (?:is )?full)|(?:user (?:is )?over quota))/i // "user is over quota" (iCloud)
],

reputation : [
/(rate limited due to IP reputation)/i
]
},

error_code : [
/(\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"
Expand All @@ -169,9 +171,7 @@ class Parser {
* Constructor
*/
constructor() {
this.__regexes = {};

this.__initRegexes();
this.__regexes = this.__initRegexes(REGEXES);
}


Expand Down Expand Up @@ -248,30 +248,31 @@ class Parser {
/**
* Initializes regexes
* @private
* @return {undefined}
* @param {object} obj
* @return {object} Regexes
*/
__initRegexes() {
for (var _key in REGEXES) {
var _key_line = `${_key}_line`;
var _entry = REGEXES[_key];
__initRegexes(obj) {
var _regexes = {};

for (var _key in obj) {
var _entry = obj[_key];

if (Array.isArray(_entry)) {
this.__regexes[_key] = [];
this.__regexes[_key_line] = [];
_regexes[_key] = [];

for (var _i = 0; _i < _entry.length; _i++) {
var _regex = _entry[_i];

this.__regexes[_key].push(
new RE2(_regex)
_regexes[_key].push(
new RE2(_entry[_i])
);
}
} else if (typeof _entry === "object" && Object.keys(_entry).length > 0) {
_regexes[_key] = this.__initRegexes(_entry);
} else {
var _regex = _entry;

this.__regexes[_key] = new RE2(_regex);
_regexes[_key] = new RE2(_entry);
}
}

return _regexes;
}


Expand Down Expand Up @@ -391,40 +392,22 @@ class Parser {
_spam = false;

// Detect enhanced-type from bounce content
var _match = loopRegexes(this.__regexes.enhanced_types_no_such_recipient, str);
for (var _key in this.__regexes.enhanced_types) {
var _match = loopRegexes(
this.__regexes.enhanced_types[_key],

if (_match && _match.length > 1) {
_type = "no_such_recipient";
}
str
);

_match = loopRegexes(this.__regexes.enhanced_types_server_unknown, str);

if (!_type && _match && _match.length > 1) {
_type = "server_unknown";
}

_match = loopRegexes(this.__regexes.enhanced_types_server_timeout, str);

if (!_type && _match && _match.length > 1) {
_type = "server_timeout";
}

_match = loopRegexes(this.__regexes.enhanced_types_mailbox_full, str);

if (!_type && _match && _match.length > 1) {
_type = "mailbox_full";
}

_match = loopRegexes(this.__regexes.enhanced_types_reputation, str);

if (!_type && _match && _match.length > 1) {
_type = "reputation";
if (!_type && _match && _match.length > 1) {
_type = _key;
}
}

// Detect enhanced-type from enhanced error code
// Notice: this is done as a last resort, as sometimes enhanced code \
// doesn't clearly convey the actual error
if (!_type && _match && code.enhanced) {
if (!_type && code.enhanced) {
_type = ERROR_CODES_TYPES[`${code.basic} ${code.enhanced}`] || null;
}

Expand Down

0 comments on commit f440a88

Please sign in to comment.