zb-email-verifier
Advanced tools
Comparing version 0.2.0 to 0.5.0
222
index.js
'use strict'; | ||
const dns = require('dns'); | ||
const net = require('net'); | ||
const P = require('bluebird'); | ||
const _ = require('lodash'); | ||
const netsend = require('./lib/netsend'); | ||
class VerifyError extends Error { | ||
constructor ( message, extra ) { | ||
super() | ||
Error.captureStackTrace( this, this.constructor ) | ||
this.name = 'CustomError' | ||
this.message = message | ||
if ( extra ) this.extra = extra; | ||
} | ||
} | ||
P.config({cancellation: true}); | ||
const dnsResolveMx = P.promisify(dns.resolveMx, {context: dns}); | ||
const netConnect = (options => { | ||
return new P((resolve, reject) => { | ||
let fnNetEnd; | ||
module.exports = { | ||
verify(opts) { | ||
const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; // eslint-disable-line | ||
const responseQueue = (() => { | ||
let msgQueue = []; | ||
let evtResolve = null; | ||
return { | ||
add(msg) { | ||
if(evtResolve) { | ||
evtResolve([msg]); | ||
evtResolve = null; | ||
} else { | ||
msgQueue.push(msg); | ||
} | ||
}, | ||
flush() { | ||
return new P((resolve, reject) => { | ||
if(msgQueue.length) { | ||
const results = _.clone(msgQueue); | ||
msgQueue = []; | ||
return resolve(results); | ||
} | ||
evtResolve = resolve; | ||
}); | ||
} | ||
}; | ||
})(); | ||
if(!emailRegex.test(opts.to)) { | ||
return P.resolve('INVALID'); | ||
} | ||
const connOption = { | ||
port: options.port, | ||
host: options.host | ||
}; | ||
const emailSplited = opts.to.split('@'); | ||
const emailHost = emailSplited[1]; | ||
const timeOut = options.timeout ? options.timeout : 0; | ||
const debug = opts.debug ? (_.isFunction(opts.debug) ? opts.debug : console.info) : () => {}; | ||
const timeout = opts.timeout ? opts.timeout : 5000; | ||
const client = net.createConnection(connOption, () => { | ||
return resolve({ | ||
write: (msg) => { | ||
client.write(msg + '\r\n'); | ||
}, | ||
end: () => { | ||
return new P((resolve, reject) => { | ||
client.end(); | ||
fnNetEnd = resolve; | ||
}); | ||
}, | ||
response: responseQueue.flush | ||
return new P((resolve, reject) => { | ||
const jobDnsResolveMx = dnsResolveMx(emailHost).then(results => { | ||
if(_.isEmpty(results)) { | ||
throw new VerifyError('','MXRECORD_FAIL'); | ||
} | ||
return results; | ||
},() => { | ||
throw new VerifyError('','MXRECORD_FAIL'); | ||
}); | ||
}).on('error', (err) => { | ||
reject(err); | ||
}); | ||
client.setTimeout(timeOut, () => { | ||
client.end(); | ||
client.destroy(new Error('timeout')); | ||
}); | ||
const jobNetConnect = jobDnsResolveMx.then(results => { | ||
debug('RESOLVE MX RECORD'); | ||
client.on('data', (() => { | ||
let response = ''; | ||
return (data) => { | ||
response += data.toString(); | ||
if(response.slice(-1) === '\n') { | ||
responseQueue.add(response.substr(0, response.length - 2)); | ||
response = ''; | ||
} | ||
}; | ||
})()); | ||
const exchange = _(results).sortBy(v => v.priority).take(1).value()[0].exchange; | ||
debug('\t' + exchange); | ||
client.on('end', () => { | ||
fnNetEnd(); | ||
}); | ||
}); | ||
}); | ||
return netsend({port: 25, host: exchange}).catch(() => { | ||
throw new VerifyError('','CONN_FAIL'); | ||
}); | ||
}); | ||
const jobVerify = jobNetConnect.then(netConn => { | ||
debug('CONNECTED SMTP SERVER'); | ||
module.exports = { | ||
verify(opts) { | ||
return netConn.response().then(resmsg => { | ||
debug('\t' + resmsg[0]); | ||
const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; // eslint-disable-line | ||
if(resmsg[0].substr(0, 3) !== '220') { | ||
throw new VerifyError('','VERIFY_FAIL'); | ||
} | ||
if(!emailRegex.test(opts.to)) { | ||
return P.resolve('INVALID'); | ||
} | ||
const writeMsg = 'HELO ' + opts.helo; | ||
debug(writeMsg); | ||
netConn.write(writeMsg); | ||
const emailSplited = opts.to.split('@'); | ||
const emailHost = emailSplited[1]; | ||
return netConn.response(); | ||
}).then(resmsg => { | ||
debug('\t' + resmsg[0]); | ||
const debug = opts.debug ? (_.isFunction(opts.debug) ? opts.debug : console.info) : () => {}; | ||
if(resmsg[0].substr(0, 3) !== '250') { | ||
throw new VerifyError('','VERIFY_FAIL'); | ||
} | ||
return dnsResolveMx(emailHost).then(results => { | ||
debug('RESOLVE MX RECORD'); | ||
const writeMsg = `MAIL FROM: <${opts.from}>`; | ||
debug(writeMsg); | ||
netConn.write(writeMsg); | ||
const exchange = _(results).sortBy(v => v.priority).take(1).value()[0].exchange; | ||
debug('\t' + exchange); | ||
return netConn.response(); | ||
}).then(resmsg => { | ||
debug('\t' + resmsg[0]); | ||
return netConnect({port: 25, host: exchange, timeout: opts.timeout}); | ||
}).then(netConn => { | ||
if(resmsg[0].substr(0, 3) !== '250') { | ||
throw new VerifyError('','VERIFY_FAIL'); | ||
} | ||
const writeMsg = `RCPT TO: <${opts.to}>`; | ||
debug(writeMsg); | ||
netConn.write(writeMsg); | ||
debug('CONNECTED SMTP SERVER'); | ||
return netConn.response(); | ||
}).then(resmsg => { | ||
debug('\t' + resmsg[0]); | ||
if(resmsg[0].substr(0, 3) === '250') { | ||
return 'EXIST'; | ||
} else { | ||
return 'NOT_EXIST'; | ||
} | ||
}).finally(() => { | ||
netConn.end(); | ||
}); | ||
}); | ||
return netConn.response().then(resmsg => { | ||
debug('\t' + resmsg[0]); | ||
const mainJob = jobVerify.then(results => { | ||
resolve(results); | ||
}).catch(VerifyError,(err) => { | ||
resolve(err.extra); | ||
}).catch((err) => { | ||
debug(err); | ||
resolve('UNKNOWN'); | ||
}); | ||
if(resmsg[0].substr(0, 3) !== '220') { | ||
return P.resolve('BLOCK'); | ||
const mainJobTimeout = setTimeout(() => { | ||
mainJob.cancel(); | ||
if(jobDnsResolveMx.isPending()) { | ||
return resolve('MXRECORD_TIMEOUT'); | ||
} | ||
const writeMsg = 'HELO ' + opts.helo; | ||
debug(writeMsg); | ||
netConn.write(writeMsg); | ||
if(jobNetConnect.isPending()) { | ||
return resolve('CONN_TIMEOUT'); | ||
} | ||
return netConn.response(); | ||
}).then(resmsg => { | ||
debug('\t' + resmsg[0]); | ||
if(resmsg[0].substr(0, 3) !== '250') { | ||
return P.resolve('BLOCK'); | ||
if(jobVerify.isPending()) { | ||
return resolve('VERIFY_TIMEOUT'); | ||
} | ||
const writeMsg = `MAIL FROM: <${opts.from}>`; | ||
debug(writeMsg); | ||
netConn.write(writeMsg); | ||
return resolve('UNKNOWN'); | ||
}, timeout); | ||
return netConn.response(); | ||
}).then(resmsg => { | ||
debug('\t' + resmsg[0]); | ||
if(resmsg[0].substr(0, 3) !== '250') { | ||
return P.resolve('BLOCK'); | ||
mainJob.finally(() => { | ||
if(!mainJob.isCancelled()) { | ||
clearTimeout(mainJobTimeout); | ||
} | ||
const writeMsg = `RCPT TO: <${opts.to}>`; | ||
debug(writeMsg); | ||
netConn.write(writeMsg); | ||
return netConn.response(); | ||
}).then(resmsg => { | ||
debug('\t' + resmsg[0]); | ||
if(resmsg[0].substr(0, 3) === '250') { | ||
return 'EXIST'; | ||
} else { | ||
return 'NOT_EXIST'; | ||
} | ||
}).finally(() => { | ||
netConn.end(); | ||
}); | ||
}).catch(() => { | ||
return 'CONN_FAIL'; | ||
}); | ||
} | ||
}; |
{ | ||
"name": "zb-email-verifier", | ||
"description": "Promise-based library for verify an email address existence via SMTP", | ||
"version": "0.2.0", | ||
"version": "0.5.0", | ||
"author": { | ||
@@ -6,0 +6,0 @@ "name": "ZIGBANG", |
@@ -12,3 +12,3 @@ 'use strict'; | ||
debug: true, | ||
timeout: 500 | ||
timeout: 1500 | ||
}).then(result => { | ||
@@ -23,7 +23,12 @@ if(result === 'EXIST') { | ||
// INVALID | ||
// MXRECORD_TIMEOUT | ||
// MXRECORD_FAIL | ||
// CONN_FAIL | ||
// CONN_TIMEOUT | ||
// VERIFY_TIMEOUT | ||
// VERIFY_FAIL | ||
// EXIST | ||
// NOT_EXIST | ||
// INVALID | ||
// BLOCK | ||
// CONN_FAIL | ||
// UNKNOWN | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
76607
22
211
3