mirror of
https://github.com/eleith/emailjs.git
synced 2024-07-05 20:10:37 +00:00
add destructuring & jsdoc comments to smtp
This commit is contained in:
parent
8c631626b4
commit
ed757b271b
313
smtp/smtp.js
313
smtp/smtp.js
@ -1,10 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
* SMTP class written using python's (2.7) smtplib.py as a base
|
* SMTP class written using python's (2.7) smtplib.py as a base
|
||||||
*/
|
*/
|
||||||
const net = require('net');
|
const { Socket } = require('net');
|
||||||
const crypto = require('crypto');
|
const { createHmac } = require('crypto');
|
||||||
const os = require('os');
|
const { hostname } = require('os');
|
||||||
const tls = require('tls');
|
const {
|
||||||
|
connect,
|
||||||
|
createSecureContext,
|
||||||
|
createSecurePair,
|
||||||
|
TLSSocket,
|
||||||
|
} = require('tls');
|
||||||
const { EventEmitter } = require('events');
|
const { EventEmitter } = require('events');
|
||||||
|
|
||||||
const SMTPResponse = require('./response');
|
const SMTPResponse = require('./response');
|
||||||
@ -24,19 +29,23 @@ const AUTH_METHODS = {
|
|||||||
const TIMEOUT = 5000;
|
const TIMEOUT = 5000;
|
||||||
let DEBUG = 0;
|
let DEBUG = 0;
|
||||||
|
|
||||||
const log = function() {
|
/**
|
||||||
|
* @param {...string} args the message(s) to log
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
const log = (...args) => {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Array.prototype.slice.call(arguments).forEach(function(d) {
|
args.forEach(d => console.log(d));
|
||||||
console.log(d);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const caller = function(callback) {
|
/**
|
||||||
if (typeof callback == 'function') {
|
* @param {Function} callback the function to call
|
||||||
const args = Array.prototype.slice.call(arguments);
|
* @param {...any} args the arguments to apply to the function
|
||||||
args.shift();
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
const caller = (callback, ...args) => {
|
||||||
|
if (typeof callback === 'function') {
|
||||||
callback.apply(null, args);
|
callback.apply(null, args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -48,6 +57,10 @@ const SMTPState = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class SMTP extends EventEmitter {
|
class SMTP extends EventEmitter {
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {{ timeout: (number | undefined), user: (string | undefined), password: (string | undefined), domain: (string | undefined), host: (string | undefined), port: (number | undefined), ssl: (boolean | undefined), tls: (boolean | undefined), authentication: (string[]) }} [options] instance options
|
||||||
|
*/
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
@ -67,7 +80,8 @@ class SMTP extends EventEmitter {
|
|||||||
authentication,
|
authentication,
|
||||||
} = Object.assign(
|
} = Object.assign(
|
||||||
{
|
{
|
||||||
domain: os.hostname(),
|
timeout: TIMEOUT,
|
||||||
|
domain: hostname(),
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
ssl: false,
|
ssl: false,
|
||||||
tls: false,
|
tls: false,
|
||||||
@ -81,48 +95,107 @@ class SMTP extends EventEmitter {
|
|||||||
options
|
options
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
this._state = SMTPState.NOTCONNECTED;
|
this._state = SMTPState.NOTCONNECTED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
this._secure = false;
|
this._secure = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {Socket}
|
||||||
|
*/
|
||||||
this.sock = null;
|
this.sock = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {{} [string]: string | boolean }
|
||||||
|
*/
|
||||||
this.features = null;
|
this.features = null;
|
||||||
this.monitor = null;
|
this.monitor = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string}[] }
|
||||||
|
*/
|
||||||
this.authentication = authentication;
|
this.authentication = authentication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}[] }
|
||||||
|
*/
|
||||||
this.timeout = timeout;
|
this.timeout = timeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string} }
|
||||||
|
*/
|
||||||
this.domain = domain;
|
this.domain = domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {string} }
|
||||||
|
*/
|
||||||
this.host = host;
|
this.host = host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
this.ssl = ssl;
|
this.ssl = ssl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
this.tls = tls;
|
this.tls = tls;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
this.port = port || (ssl ? SMTP_SSL_PORT : tls ? SMTP_TLS_PORT : SMTP_PORT);
|
this.port = port || (ssl ? SMTP_SSL_PORT : tls ? SMTP_TLS_PORT : SMTP_PORT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
this.loggedin = user && password ? false : true;
|
this.loggedin = user && password ? false : true;
|
||||||
|
|
||||||
// keep these strings hidden when quicky debugging/logging
|
// keep these strings hidden when quicky debugging/logging
|
||||||
this.user = () => options.user;
|
this.user = /** @returns {string} */ () => options.user;
|
||||||
this.password = () => options.password;
|
this.password = /** @returns {string} */ () => options.password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} level -
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
debug(level) {
|
debug(level) {
|
||||||
DEBUG = level;
|
DEBUG = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {number} the current state
|
||||||
|
*/
|
||||||
state() {
|
state() {
|
||||||
return this._state;
|
return this._state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {boolean} whether or not the instance is authorized
|
||||||
|
*/
|
||||||
authorized() {
|
authorized() {
|
||||||
return this.loggedin;
|
return this.loggedin;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(callback, port, host, options) {
|
/**
|
||||||
options = options || {};
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {number} [port] the port to use for the connection
|
||||||
this.host = host || this.host;
|
* @param {string} [host] the hostname to use for the connection
|
||||||
this.port = port || this.port;
|
* @param {{ ssl: boolean }} [options={}] the options
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
connect(callback, port = this.port, host = this.host, options = {}) {
|
||||||
|
this.port = port;
|
||||||
|
this.host = host;
|
||||||
this.ssl = options.ssl || this.ssl;
|
this.ssl = options.ssl || this.ssl;
|
||||||
|
|
||||||
if (this._state != SMTPState.NOTCONNECTED) {
|
if (this._state !== SMTPState.NOTCONNECTED) {
|
||||||
this.quit(() =>
|
this.quit(() =>
|
||||||
this.connect(
|
this.connect(
|
||||||
callback,
|
callback,
|
||||||
@ -131,7 +204,6 @@ class SMTP extends EventEmitter {
|
|||||||
options
|
options
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const connected = err => {
|
const connected = err => {
|
||||||
@ -140,7 +212,7 @@ class SMTP extends EventEmitter {
|
|||||||
|
|
||||||
if (this.ssl && !this.tls) {
|
if (this.ssl && !this.tls) {
|
||||||
// if key/ca/cert was passed in, check if connection is authorized
|
// if key/ca/cert was passed in, check if connection is authorized
|
||||||
if (typeof this.ssl != 'boolean' && !this.sock.authorized) {
|
if (typeof this.ssl !== 'boolean' && !this.sock.authorized) {
|
||||||
this.close(true);
|
this.close(true);
|
||||||
const msg = 'could not establish an ssl connection';
|
const msg = 'could not establish an ssl connection';
|
||||||
caller(callback, SMTPError(msg, SMTPError.CONNECTIONAUTH, err));
|
caller(callback, SMTPError(msg, SMTPError.CONNECTIONAUTH, err));
|
||||||
@ -188,14 +260,14 @@ class SMTP extends EventEmitter {
|
|||||||
log(`connecting: ${this.host}:${this.port}`);
|
log(`connecting: ${this.host}:${this.port}`);
|
||||||
|
|
||||||
if (this.ssl) {
|
if (this.ssl) {
|
||||||
this.sock = tls.connect(
|
this.sock = connect(
|
||||||
this.port,
|
this.port,
|
||||||
this.host,
|
this.host,
|
||||||
this.ssl,
|
this.ssl,
|
||||||
connected
|
connected
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.sock = new net.Socket();
|
this.sock = new Socket();
|
||||||
this.sock.connect(
|
this.sock.connect(
|
||||||
this.port,
|
this.port,
|
||||||
this.host,
|
this.host,
|
||||||
@ -210,8 +282,13 @@ class SMTP extends EventEmitter {
|
|||||||
this.sock.once('error', response); // the socket could reset or throw, so let's handle it and let the user know
|
this.sock.once('error', response); // the socket could reset or throw, so let's handle it and let the user know
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} str the string to send
|
||||||
|
* @param {*} callback function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
send(str, callback) {
|
send(str, callback) {
|
||||||
if (this.sock && this._state == SMTPState.CONNECTED) {
|
if (this.sock && this._state === SMTPState.CONNECTED) {
|
||||||
log(str);
|
log(str);
|
||||||
|
|
||||||
this.sock.once('response', (err, msg) => {
|
this.sock.once('response', (err, msg) => {
|
||||||
@ -232,10 +309,16 @@ class SMTP extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
command(cmd, callback, codes, failed) {
|
/**
|
||||||
|
* @param {string} cmd command to issue
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {(number[] | number)} [codes=[250]] array codes
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
command(cmd, callback, codes = [250]) {
|
||||||
codes = Array.isArray(codes)
|
codes = Array.isArray(codes)
|
||||||
? codes
|
? codes
|
||||||
: typeof codes == 'number'
|
: typeof codes === 'number'
|
||||||
? [codes]
|
? [codes]
|
||||||
: [250];
|
: [250];
|
||||||
|
|
||||||
@ -243,7 +326,7 @@ class SMTP extends EventEmitter {
|
|||||||
if (err) {
|
if (err) {
|
||||||
caller(callback, err);
|
caller(callback, err);
|
||||||
} else {
|
} else {
|
||||||
if (codes.indexOf(Number(msg.code)) != -1) {
|
if (codes.indexOf(Number(msg.code)) !== -1) {
|
||||||
caller(callback, err, msg.data, msg.message);
|
caller(callback, err, msg.data, msg.message);
|
||||||
} else {
|
} else {
|
||||||
const suffix = msg.message ? `: ${msg.message}` : '';
|
const suffix = msg.message ? `: ${msg.message}` : '';
|
||||||
@ -261,12 +344,17 @@ class SMTP extends EventEmitter {
|
|||||||
this.send(cmd + CRLF, response);
|
this.send(cmd + CRLF, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMTP 'helo' command.
|
||||||
|
*
|
||||||
|
* Hostname to send for self command defaults to the FQDN of the local
|
||||||
|
* host.
|
||||||
|
*
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {string} domain the domain to associate with the 'helo' request
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
helo(callback, domain) {
|
helo(callback, domain) {
|
||||||
/*
|
|
||||||
* SMTP 'helo' command.
|
|
||||||
* Hostname to send for self command defaults to the FQDN of the local
|
|
||||||
* host.
|
|
||||||
*/
|
|
||||||
this.command(`helo ${domain || this.domain}`, (err, data) => {
|
this.command(`helo ${domain || this.domain}`, (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
caller(callback, err);
|
caller(callback, err);
|
||||||
@ -277,6 +365,10 @@ class SMTP extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
starttls(callback) {
|
starttls(callback) {
|
||||||
const response = (err, msg) => {
|
const response = (err, msg) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -284,11 +376,11 @@ class SMTP extends EventEmitter {
|
|||||||
caller(callback, err);
|
caller(callback, err);
|
||||||
} else {
|
} else {
|
||||||
// support new API
|
// support new API
|
||||||
if (tls.TLSSocket) {
|
if (TLSSocket) {
|
||||||
const secured_socket = new tls.TLSSocket(this.sock, {
|
const secured_socket = new TLSSocket(this.sock, {
|
||||||
secureContext: tls.createSecureContext
|
secureContext: createSecureContext
|
||||||
? tls.createSecureContext(this.tls)
|
? createSecureContext(this.tls)
|
||||||
: crypto.createCredentials(this.tls),
|
: require('crypto').createCredentials(this.tls),
|
||||||
isServer: false, // older versions of node (0.12), do not default to false properly...
|
isServer: false, // older versions of node (0.12), do not default to false properly...
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -320,10 +412,10 @@ class SMTP extends EventEmitter {
|
|||||||
socket: this.sock,
|
socket: this.sock,
|
||||||
host: this.host,
|
host: this.host,
|
||||||
port: this.port,
|
port: this.port,
|
||||||
pair: tls.createSecurePair(
|
pair: createSecurePair(
|
||||||
tls.createSecureContext
|
createSecureContext
|
||||||
? tls.createSecureContext(this.tls)
|
? createSecureContext(this.tls)
|
||||||
: crypto.createCredentials(this.tls),
|
: require('crypto').createCredentials(this.tls),
|
||||||
false
|
false
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -341,6 +433,10 @@ class SMTP extends EventEmitter {
|
|||||||
this.command('starttls', response, [220]);
|
this.command('starttls', response, [220]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} data the string to parse for features
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
parse_smtp_features(data) {
|
parse_smtp_features(data) {
|
||||||
// According to RFC1869 some (badly written)
|
// According to RFC1869 some (badly written)
|
||||||
// MTA's will disconnect on an ehlo. Toss an exception if
|
// MTA's will disconnect on an ehlo. Toss an exception if
|
||||||
@ -356,7 +452,7 @@ class SMTP extends EventEmitter {
|
|||||||
// 2) There are some servers that only advertise the auth methods we
|
// 2) There are some servers that only advertise the auth methods we
|
||||||
// support using the old style.
|
// support using the old style.
|
||||||
|
|
||||||
if (parse) {
|
if (parse != null) {
|
||||||
// RFC 1869 requires a space between ehlo keyword and parameters.
|
// RFC 1869 requires a space between ehlo keyword and parameters.
|
||||||
// It's actually stricter, in that only spaces are allowed between
|
// It's actually stricter, in that only spaces are allowed between
|
||||||
// parameters, but were not going to check for that here. Note
|
// parameters, but were not going to check for that here. Note
|
||||||
@ -364,10 +460,13 @@ class SMTP extends EventEmitter {
|
|||||||
this.features[parse[1].toLowerCase()] = parse[2] || true;
|
this.features[parse[1].toLowerCase()] = parse[2] || true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {string} domain the domain to associate with the 'ehlo' request
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
ehlo(callback, domain) {
|
ehlo(callback, domain) {
|
||||||
this.features = {};
|
this.features = {};
|
||||||
this.command(`ehlo ${domain || this.domain}`, (err, data) => {
|
this.command(`ehlo ${domain || this.domain}`, (err, data) => {
|
||||||
@ -385,58 +484,117 @@ class SMTP extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} opt the features keyname to check
|
||||||
|
* @returns {boolean} whether the extension exists
|
||||||
|
*/
|
||||||
has_extn(opt) {
|
has_extn(opt) {
|
||||||
return this.features[opt.toLowerCase()] === undefined;
|
return this.features[opt.toLowerCase()] === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
help(callback, args) {
|
/**
|
||||||
// SMTP 'help' command, returns text from the server
|
* SMTP 'help' command, returns text from the server
|
||||||
this.command(args ? `help ${args}` : 'help', callback, [211, 214]);
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {string} domain the domain to associate with the 'help' request
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
help(callback, domain) {
|
||||||
|
this.command(domain ? `help ${domain}` : 'help', callback, [211, 214]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
rset(callback) {
|
rset(callback) {
|
||||||
this.command('rset', callback);
|
this.command('rset', callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
noop(callback) {
|
noop(callback) {
|
||||||
this.send('noop', callback);
|
this.send('noop', callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {string} from the sender
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
mail(callback, from) {
|
mail(callback, from) {
|
||||||
this.command(`mail FROM:${from}`, callback);
|
this.command(`mail FROM:${from}`, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {string} to the receiver
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
rcpt(callback, to) {
|
rcpt(callback, to) {
|
||||||
this.command(`RCPT TO:${to}`, callback, [250, 251]);
|
this.command(`RCPT TO:${to}`, callback, [250, 251]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
data(callback) {
|
data(callback) {
|
||||||
this.command('data', callback, [354]);
|
this.command('data', callback, [354]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
data_end(callback) {
|
data_end(callback) {
|
||||||
this.command(`${CRLF}.`, callback);
|
this.command(`${CRLF}.`, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} data the message to send
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
message(data) {
|
message(data) {
|
||||||
log(data);
|
log(data);
|
||||||
this.sock.write(data);
|
this.sock.write(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMTP 'verify' command -- checks for address validity.
|
||||||
|
*
|
||||||
|
* @param {string} address the address to validate
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
verify(address, callback) {
|
verify(address, callback) {
|
||||||
// SMTP 'verify' command -- checks for address validity.
|
|
||||||
this.command(`vrfy ${address}`, callback, [250, 251, 252]);
|
this.command(`vrfy ${address}`, callback, [250, 251, 252]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMTP 'expn' command -- expands a mailing list.
|
||||||
|
*
|
||||||
|
* @param {string} address the mailing list to expand
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
expn(address, callback) {
|
expn(address, callback) {
|
||||||
// SMTP 'expn' command -- expands a mailing list.
|
|
||||||
this.command(`expn ${address}`, callback);
|
this.command(`expn ${address}`, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls this.ehlo() and, if an error occurs, this.helo().
|
||||||
|
*
|
||||||
|
* If there has been no previous EHLO or HELO command self session, self
|
||||||
|
* method tries ESMTP EHLO first.
|
||||||
|
*
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {string} [domain] the domain to associate with the command
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
ehlo_or_helo_if_needed(callback, domain) {
|
ehlo_or_helo_if_needed(callback, domain) {
|
||||||
// Call this.ehlo() and/or this.helo() if needed.
|
// is this code callable...?
|
||||||
// If there has been no previous EHLO or HELO command self session, self
|
|
||||||
// method tries ESMTP EHLO first.
|
|
||||||
if (!this.features) {
|
if (!this.features) {
|
||||||
const response = (err, data) => caller(callback, err, data);
|
const response = (err, data) => caller(callback, err, data);
|
||||||
this.ehlo((err, data) => {
|
this.ehlo((err, data) => {
|
||||||
@ -449,6 +607,20 @@ class SMTP extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log in on an SMTP server that requires authentication.
|
||||||
|
*
|
||||||
|
* If there has been no previous EHLO or HELO command self session, self
|
||||||
|
* method tries ESMTP EHLO first.
|
||||||
|
*
|
||||||
|
* This method will return normally if the authentication was successful.
|
||||||
|
*
|
||||||
|
* @param {Function} callback function to call after response
|
||||||
|
* @param {string} [user] the username to authenticate with
|
||||||
|
* @param {string} [password] the password for the authentication
|
||||||
|
* @param {{ method: string, domain: string }} [options] login options
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
login(callback, user, password, options) {
|
login(callback, user, password, options) {
|
||||||
const login = {
|
const login = {
|
||||||
user: user ? () => user : this.user,
|
user: user ? () => user : this.user,
|
||||||
@ -464,23 +636,10 @@ class SMTP extends EventEmitter {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Log in on an SMTP server that requires authentication.
|
|
||||||
*
|
|
||||||
* The arguments are:
|
|
||||||
* - user: The user name to authenticate with.
|
|
||||||
* - password: The password for the authentication.
|
|
||||||
*
|
|
||||||
* If there has been no previous EHLO or HELO command self session, self
|
|
||||||
* method tries ESMTP EHLO first.
|
|
||||||
*
|
|
||||||
* This method will return normally if the authentication was successful.
|
|
||||||
*/
|
|
||||||
|
|
||||||
let method = null;
|
let method = null;
|
||||||
|
|
||||||
const encode_cram_md5 = challenge => {
|
const encode_cram_md5 = challenge => {
|
||||||
const hmac = crypto.createHmac('md5', login.password());
|
const hmac = createHmac('md5', login.password());
|
||||||
hmac.update(Buffer.from(challenge, 'base64').toString('ascii'));
|
hmac.update(Buffer.from(challenge, 'base64').toString('ascii'));
|
||||||
return Buffer.from(`${login.user()} ${hmac.digest('hex')}`).toString(
|
return Buffer.from(`${login.user()} ${hmac.digest('hex')}`).toString(
|
||||||
'base64'
|
'base64'
|
||||||
@ -541,9 +700,9 @@ class SMTP extends EventEmitter {
|
|||||||
if (err) {
|
if (err) {
|
||||||
failed(err, data);
|
failed(err, data);
|
||||||
} else {
|
} else {
|
||||||
if (method == AUTH_METHODS.CRAM_MD5) {
|
if (method === AUTH_METHODS.CRAM_MD5) {
|
||||||
this.command(encode_cram_md5(msg), response, [235, 503]);
|
this.command(encode_cram_md5(msg), response, [235, 503]);
|
||||||
} else if (method == AUTH_METHODS.LOGIN) {
|
} else if (method === AUTH_METHODS.LOGIN) {
|
||||||
this.command(
|
this.command(
|
||||||
Buffer.from(login.password()).toString('base64'),
|
Buffer.from(login.password()).toString('base64'),
|
||||||
response,
|
response,
|
||||||
@ -557,7 +716,7 @@ class SMTP extends EventEmitter {
|
|||||||
if (err) {
|
if (err) {
|
||||||
failed(err, data);
|
failed(err, data);
|
||||||
} else {
|
} else {
|
||||||
if (method == AUTH_METHODS.LOGIN) {
|
if (method === AUTH_METHODS.LOGIN) {
|
||||||
this.command(
|
this.command(
|
||||||
Buffer.from(login.user()).toString('base64'),
|
Buffer.from(login.user()).toString('base64'),
|
||||||
attempt,
|
attempt,
|
||||||
@ -605,7 +764,11 @@ class SMTP extends EventEmitter {
|
|||||||
this.ehlo_or_helo_if_needed(initiate, domain);
|
this.ehlo_or_helo_if_needed(initiate, domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(force) {
|
/**
|
||||||
|
* @param {boolean} [force=false] whether or not to force destroy the connection
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
close(force = false) {
|
||||||
if (this.sock) {
|
if (this.sock) {
|
||||||
if (force) {
|
if (force) {
|
||||||
log('smtp connection destroyed!');
|
log('smtp connection destroyed!');
|
||||||
@ -628,6 +791,10 @@ class SMTP extends EventEmitter {
|
|||||||
this.loggedin = !(this.user() && this.password());
|
this.loggedin = !(this.user() && this.password());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} [callback] function to call after response
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
quit(callback) {
|
quit(callback) {
|
||||||
this.command(
|
this.command(
|
||||||
'quit',
|
'quit',
|
||||||
|
Loading…
Reference in New Issue
Block a user