mirror of https://github.com/eleith/emailjs.git
refactor code to use modern language features & remove `new Buffer` calls
This commit is contained in:
parent
affddaec47
commit
99c8f5262a
|
@ -5,3 +5,5 @@
|
|||
*.swo
|
||||
*~
|
||||
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
|
|
|
@ -23,11 +23,10 @@
|
|||
"bufferjs": "1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "5.0.0",
|
||||
"chai": "1.1.0",
|
||||
"smtp-server": "^3.4.1",
|
||||
"mailparser": "2.2.0",
|
||||
"iconv": "2.2.1"
|
||||
"mocha": "5.0.0",
|
||||
"smtp-server": "^3.4.1"
|
||||
},
|
||||
"engine": [
|
||||
"node >= 6"
|
||||
|
|
348
smtp/client.js
348
smtp/client.js
|
@ -1,209 +1,187 @@
|
|||
var smtp = require('./smtp');
|
||||
var smtpError = require('./error');
|
||||
var message = require('./message');
|
||||
var addressparser= require('addressparser');
|
||||
const smtp = require('./smtp');
|
||||
const smtpError = require('./error');
|
||||
const message = require('./message');
|
||||
const addressparser = require('addressparser');
|
||||
|
||||
var Client = function(server)
|
||||
{
|
||||
this.smtp = new smtp.SMTP(server);
|
||||
//this.smtp.debug(1);
|
||||
class Client {
|
||||
constructor(server) {
|
||||
this.smtp = new smtp.SMTP(server);
|
||||
//this.smtp.debug(1);
|
||||
|
||||
this.queue = [];
|
||||
this.timer = null;
|
||||
this.sending = false;
|
||||
this.ready = false;
|
||||
};
|
||||
this.queue = [];
|
||||
this.timer = null;
|
||||
this.sending = false;
|
||||
this.ready = false;
|
||||
}
|
||||
|
||||
Client.prototype =
|
||||
{
|
||||
_poll: function()
|
||||
{
|
||||
var self = this;
|
||||
_poll() {
|
||||
clearTimeout(this.timer);
|
||||
|
||||
clearTimeout(self.timer);
|
||||
if (this.queue.length) {
|
||||
if (this.smtp.state() == smtp.state.NOTCONNECTED) {
|
||||
this._connect(this.queue[0]);
|
||||
} else if (
|
||||
this.smtp.state() == smtp.state.CONNECTED &&
|
||||
!this.sending &&
|
||||
this.ready
|
||||
) {
|
||||
this._sendmail(this.queue.shift());
|
||||
}
|
||||
}
|
||||
// wait around 1 seconds in case something does come in, otherwise close out SMTP connection if still open
|
||||
else if (this.smtp.state() == smtp.state.CONNECTED)
|
||||
this.timer = setTimeout(() => this.smtp.quit(), 1000);
|
||||
}
|
||||
|
||||
if(self.queue.length)
|
||||
{
|
||||
if(self.smtp.state() == smtp.state.NOTCONNECTED)
|
||||
self._connect(self.queue[0]);
|
||||
|
||||
else if(self.smtp.state() == smtp.state.CONNECTED && !self.sending && self.ready)
|
||||
self._sendmail(self.queue.shift());
|
||||
}
|
||||
// wait around 1 seconds in case something does come in, otherwise close out SMTP connection if still open
|
||||
else if(self.smtp.state() == smtp.state.CONNECTED)
|
||||
self.timer = setTimeout(function() { self.smtp.quit(); }, 1000);
|
||||
},
|
||||
|
||||
_connect: function(stack)
|
||||
{
|
||||
var self = this,
|
||||
|
||||
connect = function(err)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
var begin = function(err)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
self.ready = true;
|
||||
self._poll();
|
||||
}
|
||||
else {
|
||||
stack.callback(err, stack.message);
|
||||
|
||||
// clear out the queue so all callbacks can be called with the same error message
|
||||
self.queue.shift();
|
||||
self._poll();
|
||||
}
|
||||
};
|
||||
|
||||
if(!self.smtp.authorized())
|
||||
self.smtp.login(begin);
|
||||
|
||||
else
|
||||
self.smtp.ehlo_or_helo_if_needed(begin);
|
||||
}
|
||||
else {
|
||||
_connect(stack) {
|
||||
const connect = err => {
|
||||
if (!err) {
|
||||
const begin = err => {
|
||||
if (!err) {
|
||||
this.ready = true;
|
||||
this._poll();
|
||||
} else {
|
||||
stack.callback(err, stack.message);
|
||||
|
||||
// clear out the queue so all callbacks can be called with the same error message
|
||||
self.queue.shift();
|
||||
self._poll();
|
||||
}
|
||||
};
|
||||
this.queue.shift();
|
||||
this._poll();
|
||||
}
|
||||
};
|
||||
|
||||
self.ready = false;
|
||||
self.smtp.connect(connect);
|
||||
},
|
||||
if (!this.smtp.authorized()) this.smtp.login(begin);
|
||||
else this.smtp.ehlo_or_helo_if_needed(begin);
|
||||
} else {
|
||||
stack.callback(err, stack.message);
|
||||
|
||||
send: function(msg, callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if(!(msg instanceof message.Message)
|
||||
&& msg.from
|
||||
&& (msg.to || msg.cc || msg.bcc)
|
||||
&& (msg.text !== undefined || this._containsInlinedHtml(msg.attachment)))
|
||||
msg = message.create(msg);
|
||||
|
||||
if(msg instanceof message.Message)
|
||||
{
|
||||
msg.valid(function(valid, why)
|
||||
{
|
||||
if(valid)
|
||||
{
|
||||
var stack =
|
||||
{
|
||||
message: msg,
|
||||
to: addressparser(msg.header.to),
|
||||
from: addressparser(msg.header.from)[0].address,
|
||||
callback: callback || function() {}
|
||||
};
|
||||
|
||||
if(msg.header.cc)
|
||||
stack.to = stack.to.concat(addressparser(msg.header.cc));
|
||||
|
||||
if(msg.header.bcc)
|
||||
stack.to = stack.to.concat(addressparser(msg.header.bcc));
|
||||
|
||||
if(msg.header['return-path'] && addressparser(msg.header['return-path']).length)
|
||||
stack.returnPath = addressparser(msg.header['return-path'])[0].address;
|
||||
|
||||
self.queue.push(stack);
|
||||
self._poll();
|
||||
}
|
||||
else
|
||||
callback(new Error(why), msg);
|
||||
});
|
||||
// clear out the queue so all callbacks can be called with the same error message
|
||||
this.queue.shift();
|
||||
this._poll();
|
||||
}
|
||||
else
|
||||
callback(new Error("message is not a valid Message instance"), msg);
|
||||
},
|
||||
};
|
||||
|
||||
_containsInlinedHtml: function(attachment) {
|
||||
if (Array.isArray(attachment)) {
|
||||
return attachment.some((function(ctx) {
|
||||
return function(att) {
|
||||
return ctx._isAttachmentInlinedHtml(att);
|
||||
};
|
||||
})(this));
|
||||
} else {
|
||||
return this._isAttachmentInlinedHtml(attachment);
|
||||
}
|
||||
},
|
||||
this.ready = false;
|
||||
this.smtp.connect(connect);
|
||||
}
|
||||
|
||||
_isAttachmentInlinedHtml: function(attachment) {
|
||||
return attachment &&
|
||||
(attachment.data || attachment.path) &&
|
||||
attachment.alternative === true;
|
||||
},
|
||||
send(msg, callback) {
|
||||
if (
|
||||
!(msg instanceof message.Message) &&
|
||||
msg.from &&
|
||||
(msg.to || msg.cc || msg.bcc) &&
|
||||
(msg.text !== undefined || this._containsInlinedHtml(msg.attachment))
|
||||
)
|
||||
msg = message.create(msg);
|
||||
|
||||
_sendsmtp: function(stack, next)
|
||||
{
|
||||
var self = this;
|
||||
var check= function(err)
|
||||
{
|
||||
if(!err && next)
|
||||
{
|
||||
next.apply(self, [stack]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we snag on SMTP commands, call done, passing the error
|
||||
// but first reset SMTP state so queue can continue polling
|
||||
self.smtp.rset(function() { self._senddone(err, stack); });
|
||||
}
|
||||
};
|
||||
if (msg instanceof message.Message) {
|
||||
msg.valid((valid, why) => {
|
||||
if (valid) {
|
||||
const stack = {
|
||||
message: msg,
|
||||
to: addressparser(msg.header.to),
|
||||
from: addressparser(msg.header.from)[0].address,
|
||||
callback: (callback || function() {}).bind(this),
|
||||
};
|
||||
|
||||
return check;
|
||||
},
|
||||
if (msg.header.cc)
|
||||
stack.to = stack.to.concat(addressparser(msg.header.cc));
|
||||
|
||||
_sendmail: function(stack)
|
||||
{
|
||||
var self = this;
|
||||
var from = stack.returnPath || stack.from;
|
||||
self.sending = true;
|
||||
self.smtp.mail(self._sendsmtp(stack, self._sendrcpt), '<' + from + '>');
|
||||
},
|
||||
if (msg.header.bcc)
|
||||
stack.to = stack.to.concat(addressparser(msg.header.bcc));
|
||||
|
||||
_sendrcpt: function(stack)
|
||||
{
|
||||
var self = this, to = stack.to.shift().address;
|
||||
self.smtp.rcpt(self._sendsmtp(stack, stack.to.length ? self._sendrcpt : self._senddata), '<'+ to +'>');
|
||||
},
|
||||
if (
|
||||
msg.header['return-path'] &&
|
||||
addressparser(msg.header['return-path']).length
|
||||
)
|
||||
stack.returnPath = addressparser(
|
||||
msg.header['return-path']
|
||||
)[0].address;
|
||||
|
||||
_senddata: function(stack)
|
||||
{
|
||||
var self = this;
|
||||
self.smtp.data(self._sendsmtp(stack, self._sendmessage));
|
||||
},
|
||||
this.queue.push(stack);
|
||||
this._poll();
|
||||
} else {
|
||||
callback(new Error(why), msg);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback(new Error('message is not a valid Message instance'), msg);
|
||||
};
|
||||
}
|
||||
|
||||
_sendmessage: function(stack)
|
||||
{
|
||||
var self = this, stream = stack.message.stream();
|
||||
_containsInlinedHtml(attachment) {
|
||||
if (Array.isArray(attachment)) {
|
||||
return attachment.some(() => {
|
||||
return att => {
|
||||
return this._isAttachmentInlinedHtml(att);
|
||||
};
|
||||
});
|
||||
} else {
|
||||
return this._isAttachmentInlinedHtml(attachment);
|
||||
}
|
||||
}
|
||||
|
||||
stream.on('data', function(data) { self.smtp.message(data); });
|
||||
stream.on('end', function() { self.smtp.data_end(self._sendsmtp(stack, function() { self._senddone(null, stack) })); });
|
||||
_isAttachmentInlinedHtml(attachment) {
|
||||
return (
|
||||
attachment &&
|
||||
(attachment.data || attachment.path) &&
|
||||
attachment.alternative === true
|
||||
);
|
||||
}
|
||||
|
||||
// there is no way to cancel a message while in the DATA portion, so we have to close the socket to prevent
|
||||
// a bad email from going out
|
||||
stream.on('error', function(err) { self.smtp.close(); self._senddone(err, stack); });
|
||||
},
|
||||
_sendsmtp(stack, next) {
|
||||
return err => {
|
||||
if (!err && next) {
|
||||
next.apply(this, [stack]);
|
||||
} else {
|
||||
// if we snag on SMTP commands, call done, passing the error
|
||||
// but first reset SMTP state so queue can continue polling
|
||||
this.smtp.rset(() => this._senddone(err, stack));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
_senddone: function(err, stack)
|
||||
{
|
||||
var self = this;
|
||||
self.sending = false;
|
||||
stack.callback(err, stack.message);
|
||||
self._poll();
|
||||
}
|
||||
};
|
||||
_sendmail(stack) {
|
||||
const from = stack.returnPath || stack.from;
|
||||
this.sending = true;
|
||||
this.smtp.mail(this._sendsmtp(stack, this._sendrcpt), '<' + from + '>');
|
||||
}
|
||||
|
||||
_sendrcpt(stack) {
|
||||
const to = stack.to.shift().address;
|
||||
this.smtp.rcpt(
|
||||
this._sendsmtp(stack, stack.to.length ? this._sendrcpt : this._senddata),
|
||||
'<' + to + '>'
|
||||
);
|
||||
}
|
||||
|
||||
_senddata(stack) {
|
||||
this.smtp.data(this._sendsmtp(stack, this._sendmessage));
|
||||
}
|
||||
|
||||
_sendmessage(stack) {
|
||||
const stream = stack.message.stream();
|
||||
|
||||
stream.on('data', (data) => this.smtp.message(data));
|
||||
stream.on('end', () => {
|
||||
this.smtp.data_end(
|
||||
this._sendsmtp(stack, () => this._senddone(null, stack))
|
||||
);
|
||||
});
|
||||
|
||||
// there is no way to cancel a message while in the DATA portion,
|
||||
// so we have to close the socket to prevent a bad email from going out
|
||||
stream.on('error', (err) => {
|
||||
this.smtp.close();
|
||||
this._senddone(err, stack);
|
||||
});
|
||||
}
|
||||
|
||||
_senddone(err, stack) {
|
||||
this.sending = false;
|
||||
stack.callback(err, stack.message);
|
||||
this._poll();
|
||||
}
|
||||
}
|
||||
|
||||
exports.Client = Client;
|
||||
|
||||
exports.connect = function(server)
|
||||
{
|
||||
return new Client(server);
|
||||
};
|
||||
exports.connect = server => new Client(server);
|
||||
|
|
|
@ -1,14 +1,19 @@
|
|||
module.exports = function(message, code, error, smtp) {
|
||||
var err = new Error((error && error.message) ? message + ' (' + error.message + ')' : message);
|
||||
err.code = code;
|
||||
if(error)
|
||||
err.previous = error;
|
||||
const err = new Error(
|
||||
error && error.message ? `${message} (${error.message})` : message
|
||||
);
|
||||
|
||||
err.code = code;
|
||||
err.smtp = smtp;
|
||||
|
||||
if (error) {
|
||||
err.previous = error;
|
||||
}
|
||||
|
||||
return err;
|
||||
};
|
||||
|
||||
module.exports.COULDNOTCONNECT = 1;
|
||||
module.exports.COULDNOTCONNECT = 1;
|
||||
module.exports.BADRESPONSE = 2;
|
||||
module.exports.AUTHFAILED = 3;
|
||||
module.exports.TIMEDOUT = 4;
|
||||
|
|
975
smtp/message.js
975
smtp/message.js
File diff suppressed because it is too large
Load Diff
123
smtp/response.js
123
smtp/response.js
|
@ -1,81 +1,68 @@
|
|||
var SMTPError = require('./error');
|
||||
const SMTPError = require('./error');
|
||||
|
||||
var SMTPResponse = function(stream, timeout, onerror)
|
||||
{
|
||||
var buffer = '',
|
||||
class SMTPResponse {
|
||||
constructor(stream, timeout, onerror) {
|
||||
let buffer = '';
|
||||
|
||||
notify = function()
|
||||
{
|
||||
if(buffer.length)
|
||||
{
|
||||
// parse buffer for response codes
|
||||
var line = buffer.replace("\r", '');
|
||||
|
||||
if(!line.trim().split(/\n/).pop().match(/^(\d{3})\s/))
|
||||
return;
|
||||
|
||||
var match = line ? line.match(/(\d+)\s?(.*)/) : null;
|
||||
const notify = () => {
|
||||
if (buffer.length) {
|
||||
// parse buffer for response codes
|
||||
const line = buffer.replace('\r', '');
|
||||
if (!line.trim().split(/\n/).pop().match(/^(\d{3})\s/)) {
|
||||
return;
|
||||
}
|
||||
|
||||
stream.emit('response', null, match ? {code:match[1], message:match[2], data:line} : {code:-1, data:line});
|
||||
buffer = '';
|
||||
}
|
||||
},
|
||||
const match = line ? line.match(/(\d+)\s?(.*)/) : null;
|
||||
const data = match !== null
|
||||
? { code: match[1], message: match[2], data: line }
|
||||
: { code: -1, data: line };
|
||||
|
||||
error = function(err)
|
||||
{
|
||||
stream.emit('response', SMTPError('connection encountered an error', SMTPError.ERROR, err));
|
||||
},
|
||||
stream.emit('response', null, data);
|
||||
buffer = '';
|
||||
}
|
||||
};
|
||||
|
||||
timedout = function(err)
|
||||
{
|
||||
stream.end();
|
||||
stream.emit('response', SMTPError('timedout while connecting to smtp server', SMTPError.TIMEDOUT, err));
|
||||
},
|
||||
const error = (err) => {
|
||||
stream.emit('response', SMTPError('connection encountered an error', SMTPError.ERROR, err));
|
||||
}
|
||||
|
||||
watch = function(data)
|
||||
{
|
||||
//var data = stream.read();
|
||||
if (data !== null) {
|
||||
var decoded = data.toString();
|
||||
var emit = false;
|
||||
var code = 0;
|
||||
const timedout = (err) => {
|
||||
stream.end();
|
||||
stream.emit('response', SMTPError('timedout while connecting to smtp server', SMTPError.TIMEDOUT, err));
|
||||
}
|
||||
|
||||
buffer += decoded;
|
||||
notify();
|
||||
}
|
||||
},
|
||||
const watch = (data) => {
|
||||
if (data !== null) {
|
||||
buffer += data.toString();
|
||||
notify();
|
||||
}
|
||||
};
|
||||
|
||||
close = function(err)
|
||||
{
|
||||
stream.emit('response', SMTPError('connection has closed', SMTPError.CONNECTIONCLOSED, err));
|
||||
},
|
||||
const close = (err) => {
|
||||
stream.emit('response', SMTPError('connection has closed', SMTPError.CONNECTIONCLOSED, err));
|
||||
};
|
||||
|
||||
end = function(err)
|
||||
{
|
||||
stream.emit('response', SMTPError('connection has ended', SMTPError.CONNECTIONENDED, err));
|
||||
};
|
||||
const end = (err) => {
|
||||
stream.emit('response', SMTPError('connection has ended', SMTPError.CONNECTIONENDED, err));
|
||||
};
|
||||
|
||||
this.stop = function(err) {
|
||||
stream.removeAllListeners('response');
|
||||
//stream.removeListener('readable', watch);
|
||||
stream.removeListener('data', watch);
|
||||
stream.removeListener('end', end);
|
||||
stream.removeListener('close', close);
|
||||
stream.removeListener('error', error);
|
||||
this.stop = (err) => {
|
||||
stream.removeAllListeners('response');
|
||||
stream.removeListener('data', watch);
|
||||
stream.removeListener('end', end);
|
||||
stream.removeListener('close', close);
|
||||
stream.removeListener('error', error);
|
||||
|
||||
if(err && typeof(onerror) == "function")
|
||||
onerror(err);
|
||||
};
|
||||
if (err && typeof onerror === 'function')
|
||||
onerror(err);
|
||||
};
|
||||
|
||||
//stream.on('readable', watch);
|
||||
stream.on('data', watch);
|
||||
stream.on('end', end);
|
||||
stream.on('close', close);
|
||||
stream.on('error', error);
|
||||
stream.setTimeout(timeout, timedout);
|
||||
};
|
||||
stream.on('data', watch);
|
||||
stream.on('end', end);
|
||||
stream.on('close', close);
|
||||
stream.on('error', error);
|
||||
stream.setTimeout(timeout, timedout);
|
||||
}
|
||||
}
|
||||
|
||||
exports.monitor = function(stream, timeout, onerror)
|
||||
{
|
||||
return new SMTPResponse(stream, timeout, onerror);
|
||||
};
|
||||
exports.monitor = (stream, timeout, onerror) => new SMTPResponse(stream, timeout, onerror);
|
||||
|
|
699
smtp/smtp.js
699
smtp/smtp.js
|
@ -1,30 +1,30 @@
|
|||
/*
|
||||
* SMTP class written using python's (2.7) smtplib.py as a base
|
||||
*/
|
||||
var net = require('net');
|
||||
var crypto = require('crypto');
|
||||
var os = require('os');
|
||||
var tls = require('tls');
|
||||
var util = require('util');
|
||||
var events = require('events');
|
||||
const net = require('net');
|
||||
const crypto = require('crypto');
|
||||
const os = require('os');
|
||||
const tls = require('tls');
|
||||
const { EventEmitter } = require('events');
|
||||
|
||||
var SMTPResponse = require('./response');
|
||||
var SMTPError = require('./error');
|
||||
const SMTPResponse = require('./response');
|
||||
const SMTPError = require('./error');
|
||||
|
||||
var SMTP_PORT = 25;
|
||||
var SMTP_SSL_PORT = 465;
|
||||
var SMTP_TLS_PORT = 587;
|
||||
var CRLF = "\r\n";
|
||||
var AUTH_METHODS = {
|
||||
const SMTP_PORT = 25;
|
||||
const SMTP_SSL_PORT = 465;
|
||||
const SMTP_TLS_PORT = 587;
|
||||
const CRLF = '\r\n';
|
||||
const AUTH_METHODS = {
|
||||
PLAIN: 'PLAIN',
|
||||
CRAM_MD5: 'CRAM-MD5',
|
||||
LOGIN: 'LOGIN',
|
||||
XOAUTH2: 'XOAUTH2'
|
||||
};
|
||||
var TIMEOUT = 5000;
|
||||
var DEBUG = 0;
|
||||
|
||||
var log = function() {
|
||||
const TIMEOUT = 5000;
|
||||
let DEBUG = 0;
|
||||
|
||||
const log = function() {
|
||||
if (DEBUG) {
|
||||
Array.prototype.slice.call(arguments).forEach(function(d) {
|
||||
console.log(d);
|
||||
|
@ -32,7 +32,7 @@ var log = function() {
|
|||
}
|
||||
};
|
||||
|
||||
var quotedata = function(data) {
|
||||
const quotedata = function(data) {
|
||||
// Quote data for email.
|
||||
// Double leading '.', and change Unix newline '\\n', or Mac '\\r' into
|
||||
// Internet CRLF end-of-line.
|
||||
|
@ -40,274 +40,268 @@ var quotedata = function(data) {
|
|||
return data.replace(/(?:\r\n|\n|\r(?!\n))/g, CRLF).replace(/^\./gm, '..');
|
||||
};
|
||||
|
||||
var caller = function(callback) {
|
||||
const caller = function(callback) {
|
||||
if (typeof(callback) == 'function') {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
const args = Array.prototype.slice.call(arguments);
|
||||
args.shift();
|
||||
|
||||
callback.apply(null, args);
|
||||
}
|
||||
};
|
||||
|
||||
var SMTPState = {
|
||||
const SMTPState = {
|
||||
NOTCONNECTED: 0,
|
||||
CONNECTING: 1,
|
||||
CONNECTED: 2
|
||||
};
|
||||
|
||||
var SMTP = function(options) {
|
||||
events.EventEmitter.call(this);
|
||||
class SMTP extends EventEmitter {
|
||||
constructor(options = {}) {
|
||||
super();
|
||||
|
||||
options = options || {};
|
||||
const {
|
||||
timeout,
|
||||
user,
|
||||
password,
|
||||
domain,
|
||||
host,
|
||||
port,
|
||||
ssl,
|
||||
tls,
|
||||
authentication,
|
||||
} = Object.assign({
|
||||
timeout: TIMEOUT,
|
||||
domain: os.hostname(),
|
||||
host: 'localhost',
|
||||
ssl: false,
|
||||
tls: false,
|
||||
authentication: [
|
||||
AUTH_METHODS.CRAM_MD5,
|
||||
AUTH_METHODS.LOGIN,
|
||||
AUTH_METHODS.PLAIN,
|
||||
AUTH_METHODS.XOAUTH2,
|
||||
],
|
||||
}, options);
|
||||
|
||||
this.sock = null;
|
||||
this.timeout = options.timeout || TIMEOUT;
|
||||
this.features = null;
|
||||
this._state = SMTPState.NOTCONNECTED;
|
||||
this._secure = false;
|
||||
this.loggedin = (options.user && options.password) ? false : true;
|
||||
this.domain = options.domain || os.hostname();
|
||||
this.host = options.host || 'localhost';
|
||||
this.port = options.port || (options.ssl ? SMTP_SSL_PORT : options.tls ? SMTP_TLS_PORT : SMTP_PORT);
|
||||
this.ssl = options.ssl || false;
|
||||
this.tls = options.tls || false;
|
||||
this.monitor = null;
|
||||
this.authentication = options.authentication || [AUTH_METHODS.CRAM_MD5, AUTH_METHODS.LOGIN, AUTH_METHODS.PLAIN, AUTH_METHODS.XOAUTH2];
|
||||
this._state = SMTPState.NOTCONNECTED;
|
||||
this._secure = false;
|
||||
|
||||
// keep these strings hidden when quicky debugging/logging
|
||||
this.user = function() {
|
||||
return options.user;
|
||||
};
|
||||
this.password = function() {
|
||||
return options.password;
|
||||
};
|
||||
};
|
||||
this.sock = null;
|
||||
this.features = null;
|
||||
this.monitor = null;
|
||||
|
||||
SMTP.prototype = {
|
||||
debug: function(level) {
|
||||
DEBUG = level;
|
||||
},
|
||||
this.authentication = authentication;
|
||||
this.timeout = timeout;
|
||||
this.domain = domain;
|
||||
this.host = host;
|
||||
this.ssl = ssl;
|
||||
this.tls = tls;
|
||||
|
||||
state: function() {
|
||||
this.port = port || (ssl ? SMTP_SSL_PORT : tls ? SMTP_TLS_PORT : SMTP_PORT);
|
||||
this.loggedin = (user && password) ? false : true;
|
||||
|
||||
// keep these strings hidden when quicky debugging/logging
|
||||
this.user = () => options.user;
|
||||
this.password = () => options.password;
|
||||
}
|
||||
|
||||
debug(level) {
|
||||
DEBUG = level;
|
||||
}
|
||||
|
||||
state() {
|
||||
return this._state;
|
||||
},
|
||||
}
|
||||
|
||||
authorized: function() {
|
||||
authorized() {
|
||||
return this.loggedin;
|
||||
},
|
||||
}
|
||||
|
||||
connect: function(callback, port, host, options) {
|
||||
connect(callback, port, host, options) {
|
||||
options = options || {};
|
||||
|
||||
var self = this;
|
||||
this.host = host || this.host;
|
||||
this.port = port || this.port;
|
||||
this.ssl = options.ssl || this.ssl;
|
||||
|
||||
self.host = host || self.host;
|
||||
self.port = port || self.port;
|
||||
self.ssl = options.ssl || self.ssl;
|
||||
|
||||
if (self._state != SMTPState.NOTCONNECTED) {
|
||||
self.quit(function() {
|
||||
self.connect(callback, port, host, options);
|
||||
});
|
||||
if (this._state != SMTPState.NOTCONNECTED) {
|
||||
this.quit(() => this.connect(callback, port, host, options));
|
||||
return;
|
||||
}
|
||||
|
||||
var connected = function(err) {
|
||||
const connected = (err) => {
|
||||
if (!err) {
|
||||
log("connected: " + self.host + ":" + self.port);
|
||||
log(`connected: ${this.host}:${this.port}`);
|
||||
|
||||
if (self.ssl && !self.tls) {
|
||||
if (this.ssl && !this.tls) {
|
||||
// if key/ca/cert was passed in, check if connection is authorized
|
||||
if (typeof(self.ssl) != 'boolean' && !self.sock.authorized) {
|
||||
self.close(true);
|
||||
caller(callback, SMTPError('could not establish an ssl connection', SMTPError.CONNECTIONAUTH, err));
|
||||
} else self._secure = true;
|
||||
if (typeof(this.ssl) != 'boolean' && !this.sock.authorized) {
|
||||
this.close(true);
|
||||
const msg = 'could not establish an ssl connection';
|
||||
caller(callback, SMTPError(msg, SMTPError.CONNECTIONAUTH, err));
|
||||
} else {
|
||||
this._secure = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.close(true);
|
||||
caller(callback, SMTPError("could not connect", SMTPError.COULDNOTCONNECT, err));
|
||||
this.close(true);
|
||||
caller(callback, SMTPError('could not connect', SMTPError.COULDNOTCONNECT, err));
|
||||
}
|
||||
};
|
||||
|
||||
var response = function(err, msg) {
|
||||
const response = (err, msg) => {
|
||||
if (err) {
|
||||
if (self._state === SMTPState.NOTCONNECTED && !self.sock) {
|
||||
if (this._state === SMTPState.NOTCONNECTED && !this.sock) {
|
||||
return;
|
||||
}
|
||||
self.close(true);
|
||||
this.close(true);
|
||||
caller(callback, err);
|
||||
} else if (msg.code == '220') {
|
||||
log(msg.data);
|
||||
|
||||
// might happen first, so no need to wait on connected()
|
||||
self._state = SMTPState.CONNECTED;
|
||||
this._state = SMTPState.CONNECTED;
|
||||
caller(callback, null, msg.data);
|
||||
} else {
|
||||
log("response (data): " + msg.data);
|
||||
self.quit(function() {
|
||||
caller(callback, SMTPError("bad response on connection", SMTPError.BADRESPONSE, err, msg.data));
|
||||
log(`response (data): ${msg.data}`);
|
||||
this.quit(() => {
|
||||
const err = SMTPError('bad response on connection', SMTPError.BADRESPONSE, err, msg.data);
|
||||
caller(callback, err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
self._state = SMTPState.CONNECTING;
|
||||
log("connecting: " + self.host + ":" + self.port);
|
||||
this._state = SMTPState.CONNECTING;
|
||||
log(`connecting: ${this.host}:${this.port}`);
|
||||
|
||||
if (self.ssl) {
|
||||
self.sock = tls.connect(self.port, self.host, self.ssl, connected);
|
||||
if (this.ssl) {
|
||||
this.sock = tls.connect(this.port, this.host, this.ssl, connected);
|
||||
} else {
|
||||
self.sock = new net.Socket();
|
||||
self.sock.connect(self.port, self.host, connected);
|
||||
this.sock = new net.Socket();
|
||||
this.sock.connect(this.port, this.host, connected);
|
||||
}
|
||||
|
||||
self.monitor = SMTPResponse.monitor(self.sock, self.timeout, function() {
|
||||
self.close(true);
|
||||
});
|
||||
self.sock.once('response', response);
|
||||
self.sock.once('error', response); // the socket could reset or throw, so let's handle it and let the user know
|
||||
},
|
||||
this.monitor = SMTPResponse.monitor(this.sock, this.timeout, () => this.close(true));
|
||||
this.sock.once('response', response);
|
||||
this.sock.once('error', response); // the socket could reset or throw, so let's handle it and let the user know
|
||||
}
|
||||
|
||||
send: function(str, callback) {
|
||||
var self = this;
|
||||
|
||||
if (self.sock && self._state == SMTPState.CONNECTED) {
|
||||
send(str, callback) {
|
||||
if (this.sock && this._state == SMTPState.CONNECTED) {
|
||||
log(str);
|
||||
|
||||
var response = function(err, msg) {
|
||||
this.sock.once('response', (err, msg) => {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
} else {
|
||||
log(msg.data);
|
||||
caller(callback, null, msg);
|
||||
}
|
||||
};
|
||||
|
||||
self.sock.once('response', response);
|
||||
self.sock.write(str);
|
||||
});
|
||||
this.sock.write(str);
|
||||
} else {
|
||||
self.close(true);
|
||||
this.close(true);
|
||||
caller(callback, SMTPError('no connection has been established', SMTPError.NOCONNECTION));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
command: function(cmd, callback, codes, failed) {
|
||||
command(cmd, callback, codes, failed) {
|
||||
codes = Array.isArray(codes) ? codes : typeof(codes) == 'number' ? [codes] : [250];
|
||||
|
||||
var response = function(err, msg) {
|
||||
const response = (err, msg) => {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
} else {
|
||||
if (codes.indexOf(Number(msg.code)) != -1) {
|
||||
caller(callback, err, msg.data, msg.message);
|
||||
} else {
|
||||
var errorMessage = "bad response on command '" + cmd.split(' ')[0] + "'";
|
||||
if (msg.message) {
|
||||
errorMessage += ': ' + msg.message;
|
||||
}
|
||||
const suffix = msg.message ? `: ${msg.message}` : '';
|
||||
const errorMessage = `bad response on command '${cmd.split(' ')[0]}'${suffix}`;
|
||||
caller(callback, SMTPError(errorMessage, SMTPError.BADRESPONSE, null, msg.data));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.send(cmd + CRLF, response);
|
||||
},
|
||||
}
|
||||
|
||||
helo: function(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) => {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
} else {
|
||||
this.parse_smtp_features(data);
|
||||
caller(callback, err, data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var self = this,
|
||||
|
||||
response = function(err, data) {
|
||||
starttls(callback) {
|
||||
const response = (err, msg) => {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
} else {
|
||||
self.parse_smtp_features(data);
|
||||
caller(callback, err, data);
|
||||
}
|
||||
};
|
||||
|
||||
this.command("helo " + (domain || this.domain), response);
|
||||
},
|
||||
|
||||
starttls: function(callback) {
|
||||
var self = this,
|
||||
|
||||
response = function(err, msg) {
|
||||
if (err) {
|
||||
err.message += " while establishing a starttls session";
|
||||
err.message += ' while establishing a starttls session';
|
||||
caller(callback, err);
|
||||
} else {
|
||||
// support new API
|
||||
if (tls.TLSSocket) {
|
||||
var secured_socket = new tls.TLSSocket(self.sock, {
|
||||
secureContext: tls.createSecureContext ? tls.createSecureContext(self.tls) : crypto.createCredentials(self.tls),
|
||||
const secured_socket = new tls.TLSSocket(this.sock, {
|
||||
secureContext: tls.createSecureContext ? tls.createSecureContext(this.tls) : crypto.createCredentials(this.tls),
|
||||
isServer: false // older versions of node (0.12), do not default to false properly...
|
||||
});
|
||||
|
||||
secured_socket.on('error', function(err) {
|
||||
self.close(true);
|
||||
secured_socket.on('error', (err) => {
|
||||
this.close(true);
|
||||
caller(callback, err);
|
||||
});
|
||||
|
||||
self._secure = true;
|
||||
self.sock = secured_socket;
|
||||
this._secure = true;
|
||||
this.sock = secured_socket;
|
||||
|
||||
SMTPResponse.monitor(self.sock, self.timeout, function() {
|
||||
self.close(true);
|
||||
});
|
||||
SMTPResponse.monitor(this.sock, this.timeout, () => this.close(true));
|
||||
caller(callback, msg.data);
|
||||
} else {
|
||||
var secured_socket = null;
|
||||
var secured = function() {
|
||||
self._secure = true;
|
||||
self.sock = secured_socket;
|
||||
const secured_socket = null;
|
||||
const secured = () => {
|
||||
this._secure = true;
|
||||
this.sock = secured_socket;
|
||||
|
||||
var error = function(err) {
|
||||
self.close(true);
|
||||
caller(callback, err);
|
||||
};
|
||||
|
||||
SMTPResponse.monitor(self.sock, self.timeout, function() {
|
||||
self.close(true);
|
||||
});
|
||||
SMTPResponse.monitor(this.sock, this.timeout, () => this.close(true));
|
||||
caller(callback, msg.data);
|
||||
};
|
||||
|
||||
//secured_socket = starttls.secure(self.sock, self.tls, secured);
|
||||
var starttls = require('starttls');
|
||||
const starttls = require('starttls');
|
||||
secured_socket = starttls({
|
||||
socket: self.sock,
|
||||
host: self.host,
|
||||
port: self.port,
|
||||
socket: this.sock,
|
||||
host: this.host,
|
||||
port: this.port,
|
||||
pair: tls.createSecurePair(
|
||||
tls.createSecureContext ? tls.createSecureContext(self.tls) : crypto.createCredentials(self.tls),
|
||||
tls.createSecureContext ? tls.createSecureContext(this.tls) : crypto.createCredentials(this.tls),
|
||||
false)
|
||||
}, secured).cleartext;
|
||||
|
||||
secured_socket.on('error', function(err) {
|
||||
self.close(true);
|
||||
secured_socket.on('error', (err) => {
|
||||
this.close(true);
|
||||
caller(callback, err);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.command("starttls", response, [220]);
|
||||
},
|
||||
|
||||
parse_smtp_features: function(data) {
|
||||
var self = this;
|
||||
this.command('starttls', response, [220]);
|
||||
}
|
||||
|
||||
parse_smtp_features(data) {
|
||||
// According to RFC1869 some (badly written)
|
||||
// MTA's will disconnect on an ehlo. Toss an exception if
|
||||
// that happens -ddm
|
||||
|
||||
data.split("\n").forEach(function(ext) {
|
||||
var parse = ext.match(/^(?:\d+[\-=]?)\s*?([^\s]+)(?:\s+(.*)\s*?)?$/);
|
||||
data.split('\n').forEach((ext) => {
|
||||
const parse = ext.match(/^(?:\d+[\-=]?)\s*?([^\s]+)(?:\s+(.*)\s*?)?$/);
|
||||
|
||||
// To be able to communicate with as many SMTP servers as possible,
|
||||
// we have to take the old-style auth advertisement into account,
|
||||
|
@ -321,238 +315,230 @@ SMTP.prototype = {
|
|||
// It's actually stricter, in that only spaces are allowed between
|
||||
// parameters, but were not going to check for that here. Note
|
||||
// that the space isn't present if there are no parameters.
|
||||
self.features[parse[1].toLowerCase()] = parse[2] || true;
|
||||
this.features[parse[1].toLowerCase()] = parse[2] || true;
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
},
|
||||
|
||||
ehlo: function(callback, domain) {
|
||||
var self = this,
|
||||
|
||||
response = function(err, data) {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
} else {
|
||||
self.parse_smtp_features(data);
|
||||
|
||||
if (self.tls && !self._secure) {
|
||||
self.starttls(function() {
|
||||
self.ehlo(callback, domain);
|
||||
});
|
||||
} else {
|
||||
caller(callback, err, data);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ehlo(callback, domain) {
|
||||
this.features = {};
|
||||
this.command("ehlo " + (domain || this.domain), response);
|
||||
},
|
||||
this.command(`ehlo ${domain || this.domain}`, (err, data) => {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
} else {
|
||||
this.parse_smtp_features(data);
|
||||
|
||||
has_extn: function(opt) {
|
||||
if (this.tls && !this._secure) {
|
||||
this.starttls(() => this.ehlo(callback, domain));
|
||||
} else {
|
||||
caller(callback, err, data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
has_extn(opt) {
|
||||
return this.features[opt.toLowerCase()] === undefined;
|
||||
},
|
||||
}
|
||||
|
||||
help: function(callback, args) {
|
||||
help(callback, args) {
|
||||
// SMTP 'help' command, returns text from the server
|
||||
this.command(args ? "help " + args : "help", callback, [211, 214]);
|
||||
},
|
||||
this.command(args ? `help ${args}` : 'help', callback, [211, 214]);
|
||||
}
|
||||
|
||||
rset: function(callback) {
|
||||
this.command("rset", callback);
|
||||
},
|
||||
rset(callback) {
|
||||
this.command('rset', callback);
|
||||
}
|
||||
|
||||
noop: function(callback) {
|
||||
this.send("noop", callback);
|
||||
},
|
||||
noop(callback) {
|
||||
this.send('noop', callback);
|
||||
}
|
||||
|
||||
mail: function(callback, from) {
|
||||
this.command("mail FROM:" + from, callback);
|
||||
},
|
||||
mail(callback, from) {
|
||||
this.command(`mail FROM:${from}`, callback);
|
||||
}
|
||||
|
||||
rcpt: function(callback, to) {
|
||||
this.command("RCPT TO:" + to, callback, [250, 251]);
|
||||
},
|
||||
rcpt(callback, to) {
|
||||
this.command(`RCPT TO:${to}`, callback, [250, 251]);
|
||||
}
|
||||
|
||||
data: function(callback) {
|
||||
this.command("data", callback, [354]);
|
||||
},
|
||||
data(callback) {
|
||||
this.command('data', callback, [354]);
|
||||
}
|
||||
|
||||
data_end: function(callback) {
|
||||
this.command(CRLF + ".", callback);
|
||||
},
|
||||
data_end(callback) {
|
||||
this.command(`${CRLF}.`, callback);
|
||||
}
|
||||
|
||||
message: function(data) {
|
||||
message(data) {
|
||||
log(data);
|
||||
this.sock.write(data);
|
||||
},
|
||||
}
|
||||
|
||||
verify: function(address, callback) {
|
||||
// SMTP 'verify' command -- checks for address validity."""
|
||||
this.command("vrfy " + address, callback, [250, 251, 252]);
|
||||
},
|
||||
verify(address, callback) {
|
||||
// SMTP 'verify' command -- checks for address validity.
|
||||
this.command(`vrfy ${address}`, callback, [250, 251, 252]);
|
||||
}
|
||||
|
||||
expn: function(address, callback) {
|
||||
expn(address, callback) {
|
||||
// SMTP 'expn' command -- expands a mailing list.
|
||||
this.command("expn " + address, callback);
|
||||
},
|
||||
this.command(`expn ${address}`, callback);
|
||||
}
|
||||
|
||||
ehlo_or_helo_if_needed: function(callback, domain) {
|
||||
// Call self.ehlo() and/or self.helo() if needed.
|
||||
ehlo_or_helo_if_needed(callback, domain) {
|
||||
// Call this.ehlo() and/or this.helo() if needed.
|
||||
// If there has been no previous EHLO or HELO command self session, self
|
||||
// method tries ESMTP EHLO first.
|
||||
var self = this;
|
||||
|
||||
if (!this.features) {
|
||||
var response = function(err, data) {
|
||||
caller(callback, err, data);
|
||||
};
|
||||
|
||||
var attempt = function(err, data) {
|
||||
if (err) self.helo(response, domain);
|
||||
else caller(callback, err, data);
|
||||
};
|
||||
|
||||
self.ehlo(attempt, domain);
|
||||
}
|
||||
},
|
||||
|
||||
login: function(callback, user, password, options) {
|
||||
var self = this,
|
||||
|
||||
login = {
|
||||
user: user ? function() {
|
||||
return user;
|
||||
} : self.user,
|
||||
password: password ? function() {
|
||||
return password;
|
||||
} : self.password,
|
||||
method: options && options.method ? options.method.toUpperCase() : ''
|
||||
},
|
||||
|
||||
domain = options && options.domain ? options.domain : this.domain,
|
||||
|
||||
initiate = function(err, data) {
|
||||
const response = (err, data) => caller(callback, err, data);
|
||||
this.ehlo((err, data) => {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
return;
|
||||
}
|
||||
this.helo(response, domain);
|
||||
} else {
|
||||
caller(callback, err, data);
|
||||
}
|
||||
}, domain);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
login(callback, user, password, options) {
|
||||
const login = {
|
||||
user: user ? () => user : this.user,
|
||||
password: password ? () => password : this.password,
|
||||
method: options && options.method ? options.method.toUpperCase() : '',
|
||||
};
|
||||
|
||||
var method = null,
|
||||
const domain = options && options.domain ? options.domain : this.domain;
|
||||
|
||||
encode_cram_md5 = function(challenge) {
|
||||
challenge = (new Buffer(challenge, "base64")).toString("ascii");
|
||||
const initiate = (err, data) => {
|
||||
if (err) {
|
||||
caller(callback, err);
|
||||
return;
|
||||
}
|
||||
|
||||
var hmac = crypto.createHmac('md5', login.password());
|
||||
hmac.update(challenge);
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
return (new Buffer(login.user() + " " + hmac.digest('hex')).toString("base64"));
|
||||
},
|
||||
let method = null;
|
||||
|
||||
encode_plain = function() {
|
||||
return (new Buffer("\u0000" + login.user() + "\u0000" + login.password())).toString("base64");
|
||||
},
|
||||
const encode_cram_md5 = (challenge) => {
|
||||
const hmac = crypto.createHmac('md5', login.password());
|
||||
hmac.update(Buffer.from(challenge, 'base64').toString('ascii'));
|
||||
return Buffer.from(`${login.user()} ${hmac.digest('hex')}`).toString('base64');
|
||||
};
|
||||
|
||||
encode_xoauth2 = function() {
|
||||
// console.log("user=" + login.user() + "\1auth=Bearer " + login.password()+"\1\1");
|
||||
// see: https://developers.google.com/gmail/xoauth2_protocol
|
||||
return (new Buffer("user=" + login.user() + "\u0001auth=Bearer " + login.password() + "\u0001\u0001")).toString("base64");
|
||||
};
|
||||
const encode_plain = () =>
|
||||
Buffer
|
||||
.from(`\u0000${login.user()}\u0000${login.password()}`)
|
||||
.toString('base64');
|
||||
|
||||
// List of authentication methods we support: from preferred to
|
||||
// less preferred methods.
|
||||
if (!method) {
|
||||
var preferred = self.authentication;
|
||||
var auth = "";
|
||||
// see: https://developers.google.com/gmail/xoauth2_protocol
|
||||
const encode_xoauth2 = () =>
|
||||
Buffer
|
||||
.from(`user=${login.user()}\u0001auth=Bearer ${login.password()}\u0001\u0001`)
|
||||
.toString('base64');
|
||||
|
||||
if (self.features && self.features.auth) {
|
||||
if (typeof(self.features.auth) === 'string') {
|
||||
auth = self.features.auth;
|
||||
}
|
||||
}
|
||||
// List of authentication methods we support: from preferred to
|
||||
// less preferred methods.
|
||||
if (!method) {
|
||||
const preferred = this.authentication;
|
||||
let auth = '';
|
||||
|
||||
for (var i = 0; i < preferred.length; i++) {
|
||||
if (auth.indexOf(preferred[i]) != -1) {
|
||||
method = preferred[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.features && this.features.auth) {
|
||||
if (typeof(this.features.auth) === 'string') {
|
||||
auth = this.features.auth;
|
||||
}
|
||||
}
|
||||
|
||||
// handle bad responses from command differently
|
||||
var failed = function(err, data) {
|
||||
self.loggedin = false;
|
||||
self.close(); // if auth is bad, close the connection, it won't get better by itself
|
||||
caller(callback, SMTPError('authorization.failed', SMTPError.AUTHFAILED, err, data));
|
||||
};
|
||||
for (let i = 0; i < preferred.length; i++) {
|
||||
if (auth.includes(preferred[i])) {
|
||||
method = preferred[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var response = function(err, data) {
|
||||
if (err) {
|
||||
failed(err, data);
|
||||
} else {
|
||||
self.loggedin = true;
|
||||
caller(callback, err, data);
|
||||
}
|
||||
};
|
||||
// handle bad responses from command differently
|
||||
const failed = (err, data) => {
|
||||
this.loggedin = false;
|
||||
this.close(); // if auth is bad, close the connection, it won't get better by itself
|
||||
caller(callback, SMTPError('authorization.failed', SMTPError.AUTHFAILED, err, data));
|
||||
};
|
||||
|
||||
var attempt = function(err, data, msg) {
|
||||
if (err) {
|
||||
failed(err, data);
|
||||
} else {
|
||||
if (method == AUTH_METHODS.CRAM_MD5) {
|
||||
self.command(encode_cram_md5(msg), response, [235, 503]);
|
||||
} else if (method == AUTH_METHODS.LOGIN) {
|
||||
self.command((new Buffer(login.password())).toString("base64"), response, [235, 503]);
|
||||
}
|
||||
}
|
||||
};
|
||||
const response = (err, data) => {
|
||||
if (err) {
|
||||
failed(err, data);
|
||||
} else {
|
||||
this.loggedin = true;
|
||||
caller(callback, err, data);
|
||||
}
|
||||
};
|
||||
|
||||
var attempt_user = function(err, data, msg) {
|
||||
if (err) {
|
||||
failed(err, data);
|
||||
} else {
|
||||
if (method == AUTH_METHODS.LOGIN) {
|
||||
self.command((new Buffer(login.user())).toString("base64"), attempt, [334]);
|
||||
}
|
||||
}
|
||||
};
|
||||
const attempt = (err, data, msg) => {
|
||||
if (err) {
|
||||
failed(err, data);
|
||||
} else {
|
||||
if (method == AUTH_METHODS.CRAM_MD5) {
|
||||
this.command(encode_cram_md5(msg), response, [235, 503]);
|
||||
} else if (method == AUTH_METHODS.LOGIN) {
|
||||
this.command(Buffer.from(login.password()).toString('base64'), response, [235, 503]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (method == AUTH_METHODS.CRAM_MD5) self.command("AUTH " + AUTH_METHODS.CRAM_MD5, attempt, [334]);
|
||||
const attempt_user = (err, data, msg) => {
|
||||
if (err) {
|
||||
failed(err, data);
|
||||
} else {
|
||||
if (method == AUTH_METHODS.LOGIN) {
|
||||
this.command(Buffer.from(login.user()).toString('base64'), attempt, [334]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
else if (method == AUTH_METHODS.LOGIN) self.command("AUTH " + AUTH_METHODS.LOGIN, attempt_user, [334]);
|
||||
switch (method) {
|
||||
case AUTH_METHODS.CRAM_MD5:
|
||||
this.command(`AUTH ${AUTH_METHODS.CRAM_MD5}`, attempt, [334]);
|
||||
break;
|
||||
case AUTH_METHODS.LOGIN:
|
||||
this.command(`AUTH ${AUTH_METHODS.LOGIN}`, attempt_user, [334]);
|
||||
break;
|
||||
case AUTH_METHODS.PLAIN:
|
||||
this.command(`AUTH ${AUTH_METHODS.PLAIN} ${encode_plain(login.user(), login.password())}`, response, [235, 503]);
|
||||
break;
|
||||
case AUTH_METHODS.XOAUTH2:
|
||||
this.command(`AUTH ${AUTH_METHODS.XOAUTH2} ${encode_xoauth2(login.user(), login.password())}`, response, [235, 503]);
|
||||
break;
|
||||
default:
|
||||
const msg = 'no form of authorization supported';
|
||||
const err = SMTPError(msg, SMTPError.AUTHNOTSUPPORTED, null, data);
|
||||
caller(callback, err);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
else if (method == AUTH_METHODS.PLAIN) self.command("AUTH " + AUTH_METHODS.PLAIN + " " + encode_plain(login.user(), login.password()), response, [235, 503]);
|
||||
this.ehlo_or_helo_if_needed(initiate, domain);
|
||||
}
|
||||
|
||||
else if (method == AUTH_METHODS.XOAUTH2) self.command("AUTH " + AUTH_METHODS.XOAUTH2 + " " + encode_xoauth2(login.user(), login.password()), response, [235, 503]);
|
||||
|
||||
else if (!method) caller(callback, SMTPError('no form of authorization supported', SMTPError.AUTHNOTSUPPORTED, null, data));
|
||||
};
|
||||
|
||||
self.ehlo_or_helo_if_needed(initiate, domain);
|
||||
},
|
||||
|
||||
close: function(force) {
|
||||
close(force) {
|
||||
if (this.sock) {
|
||||
if (force) {
|
||||
log("smtp connection destroyed!");
|
||||
log('smtp connection destroyed!');
|
||||
this.sock.destroy();
|
||||
} else {
|
||||
log("smtp connection closed.");
|
||||
log('smtp connection closed.');
|
||||
this.sock.end();
|
||||
}
|
||||
}
|
||||
|
@ -567,21 +553,14 @@ SMTP.prototype = {
|
|||
this.sock = null;
|
||||
this.features = null;
|
||||
this.loggedin = !(this.user() && this.password());
|
||||
},
|
||||
|
||||
quit: function(callback) {
|
||||
var self = this,
|
||||
response = function(err, data) {
|
||||
caller(callback, err, data);
|
||||
self.close();
|
||||
};
|
||||
|
||||
this.command("quit", response, [221, 250]);
|
||||
}
|
||||
};
|
||||
|
||||
for (var each in events.EventEmitter.prototype) {
|
||||
SMTP.prototype[each] = events.EventEmitter.prototype[each];
|
||||
quit(callback) {
|
||||
this.command('quit', (err, data) => {
|
||||
caller(callback, err, data);
|
||||
this.close();
|
||||
}, [221, 250]);
|
||||
}
|
||||
}
|
||||
|
||||
exports.SMTP = SMTP;
|
||||
|
|
|
@ -1,60 +1,72 @@
|
|||
describe("authorize plain", function() {
|
||||
var parser = require('mailparser').simpleParser;
|
||||
var smtpServer = require("smtp-server").SMTPServer;
|
||||
var expect = require("chai").expect;
|
||||
var fs = require("fs");
|
||||
var os = require("os");
|
||||
var path = require('path');
|
||||
var email = require('../email');
|
||||
var port = 2526;
|
||||
var server = null;
|
||||
var smtp = null;
|
||||
describe('authorize plain', function() {
|
||||
const { simpleParser: parser } = require('mailparser');
|
||||
const { SMTPServer: smtpServer } = require('smtp-server');
|
||||
const { expect } = require('chai');
|
||||
const email = require('../email');
|
||||
const port = 2526;
|
||||
|
||||
var send = function(message, verify, done) {
|
||||
smtp.onData = function(stream, session, callback) {
|
||||
parser(stream).then(verify).then(done).catch(done);
|
||||
stream.on('end', callback);
|
||||
let server = null;
|
||||
let smtp = null;
|
||||
|
||||
const send = function(message, verify, done) {
|
||||
smtp.onData = function(stream, session, callback) {
|
||||
parser(stream)
|
||||
.then(verify)
|
||||
.then(done)
|
||||
.catch(done);
|
||||
stream.on('end', callback);
|
||||
};
|
||||
|
||||
server.send(message, function(err) {
|
||||
if (err) throw err;
|
||||
});
|
||||
};
|
||||
|
||||
before(function(done) {
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // prevent CERT_HAS_EXPIRED errors
|
||||
|
||||
smtp = new smtpServer({ secure: true, authMethods: ['LOGIN'] });
|
||||
smtp.listen(port, function() {
|
||||
smtp.onAuth = function(auth, session, callback) {
|
||||
if (auth.username == 'pooh' && auth.password == 'honey') {
|
||||
callback(null, { user: 'pooh' });
|
||||
} else {
|
||||
return callback(new Error('invalid user / pass'));
|
||||
}
|
||||
};
|
||||
|
||||
server.send(message, function(err) { if (err) throw err; });
|
||||
}
|
||||
server = email.server.connect({
|
||||
port: port,
|
||||
user: 'pooh',
|
||||
password: 'honey',
|
||||
ssl: true
|
||||
});
|
||||
|
||||
before(function(done) {
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // prevent CERT_HAS_EXPIRED errors
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
smtp = new smtpServer({secure: true, authMethods: ["LOGIN"]});
|
||||
smtp.listen(port, function() {
|
||||
smtp.onAuth = function(auth, session, callback) {
|
||||
if (auth.username == "pooh" && auth.password == "honey") {
|
||||
callback(null, {user: "pooh"});
|
||||
} else {
|
||||
return callback(new Error("invalid user / pass"));
|
||||
}
|
||||
}
|
||||
after(function(done) {
|
||||
smtp.close(done);
|
||||
});
|
||||
|
||||
server = email.server.connect({port:port, user:"pooh", password:"honey", ssl:true});
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('login', function(done) {
|
||||
const message = {
|
||||
subject: 'this is a test TEXT message from emailjs',
|
||||
from: 'piglet@gmail.com',
|
||||
to: 'pooh@gmail.com',
|
||||
text: 'It is hard to be brave when you\'re only a Very Small Animal.'
|
||||
};
|
||||
|
||||
after(function(done) {
|
||||
smtp.close(done);
|
||||
});
|
||||
const created = email.message.create(message);
|
||||
|
||||
it("login", function(done) {
|
||||
var message = {
|
||||
subject: "this is a test TEXT message from emailjs",
|
||||
from: "piglet@gmail.com",
|
||||
to: "pooh@gmail.com",
|
||||
text: "It is hard to be brave when you're only a Very Small Animal."
|
||||
};
|
||||
|
||||
send(email.message.create(message), function(mail) {
|
||||
expect(mail.text).to.equal(message.text + "\n\n\n");
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
}, done);
|
||||
});
|
||||
const callback = function(mail) {
|
||||
expect(mail.text).to.equal(message.text + '\n\n\n');
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
};
|
||||
|
||||
send(created, callback, done);
|
||||
});
|
||||
});
|
||||
|
|
114
test/authssl.js
114
test/authssl.js
|
@ -1,59 +1,71 @@
|
|||
describe("authorize ssl", function() {
|
||||
var parser = require('mailparser').simpleParser;
|
||||
var smtpServer = require('smtp-server').SMTPServer;
|
||||
var expect = require("chai").expect;
|
||||
var fs = require("fs");
|
||||
var os = require("os");
|
||||
var path = require('path');
|
||||
var email = require('../email');
|
||||
var port = 2526;
|
||||
var server = null;
|
||||
var smtp = null;
|
||||
describe('authorize ssl', function() {
|
||||
const { simpleParser: parser } = require('mailparser');
|
||||
const { SMTPServer: smtpServer } = require('smtp-server');
|
||||
const { expect } = require('chai');
|
||||
const email = require('../email');
|
||||
const port = 2526;
|
||||
|
||||
var send = function(message, verify, done) {
|
||||
smtp.onData = function(stream, session, callback) {
|
||||
parser(stream).then(verify).then(done).catch(done);
|
||||
stream.on('end', callback);
|
||||
let server = null;
|
||||
let smtp = null;
|
||||
|
||||
const send = function(message, verify, done) {
|
||||
smtp.onData = function(stream, session, callback) {
|
||||
parser(stream)
|
||||
.then(verify)
|
||||
.then(done)
|
||||
.catch(done);
|
||||
stream.on('end', callback);
|
||||
};
|
||||
|
||||
server.send(message, function(err) {
|
||||
if (err) throw err;
|
||||
});
|
||||
};
|
||||
|
||||
before(function(done) {
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // prevent CERT_HAS_EXPIRED errors
|
||||
|
||||
smtp = new smtpServer({ secure: true, authMethods: ['LOGIN'] });
|
||||
smtp.listen(port, function() {
|
||||
smtp.onAuth = function(auth, session, callback) {
|
||||
if (auth.username == 'pooh' && auth.password == 'honey') {
|
||||
callback(null, { user: 'pooh' });
|
||||
} else {
|
||||
return callback(new Error('invalid user / pass'));
|
||||
}
|
||||
};
|
||||
|
||||
server.send(message, function(err) { if (err) throw err; });
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // prevent CERT_HAS_EXPIRED errors
|
||||
|
||||
smtp = new smtpServer({secure: true, authMethods: ["LOGIN"]});
|
||||
smtp.listen(port, function() {
|
||||
smtp.onAuth = function(auth, session, callback) {
|
||||
if (auth.username == "pooh" && auth.password == "honey") {
|
||||
callback(null, {user: "pooh"});
|
||||
} else {
|
||||
return callback(new Error("invalid user / pass"));
|
||||
}
|
||||
}
|
||||
|
||||
server = email.server.connect({port:port, user:"pooh", password:"honey", ssl:true});
|
||||
done();
|
||||
server = email.server.connect({
|
||||
port: port,
|
||||
user: 'pooh',
|
||||
password: 'honey',
|
||||
ssl: true
|
||||
});
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
smtp.close(done);
|
||||
});
|
||||
after(function(done) {
|
||||
smtp.close(done);
|
||||
});
|
||||
|
||||
it("login", function(done) {
|
||||
var message = {
|
||||
subject: "this is a test TEXT message from emailjs",
|
||||
from: "pooh@gmail.com",
|
||||
to: "rabbit@gmail.com",
|
||||
text: "hello friend, i hope this message finds you well."
|
||||
};
|
||||
it('login', function(done) {
|
||||
const message = {
|
||||
subject: 'this is a test TEXT message from emailjs',
|
||||
from: 'pooh@gmail.com',
|
||||
to: 'rabbit@gmail.com',
|
||||
text: 'hello friend, i hope this message finds you well.'
|
||||
};
|
||||
|
||||
send(email.message.create(message), function(mail) {
|
||||
expect(mail.text).to.equal(message.text + "\n\n\n");
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
email.message.create(message),
|
||||
function(mail) {
|
||||
expect(mail.text).to.equal(message.text + '\n\n\n');
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
718
test/message.js
718
test/message.js
|
@ -1,329 +1,455 @@
|
|||
describe("messages", function() {
|
||||
var parser = require('mailparser').simpleParser;
|
||||
var smtpServer = require('smtp-server').SMTPServer;
|
||||
var expect = require("chai").expect;
|
||||
var fs = require("fs");
|
||||
var os = require("os");
|
||||
var path = require('path');
|
||||
var email = require('../email');
|
||||
var port = 2526;
|
||||
var server = null;
|
||||
var smtp = null;
|
||||
describe('messages', function() {
|
||||
const { simpleParser: parser } = require('mailparser');
|
||||
const { SMTPServer: smtpServer } = require('smtp-server');
|
||||
const { expect } = require('chai');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const email = require('../email');
|
||||
const port = 2526;
|
||||
|
||||
var send = function(message, verify, done) {
|
||||
smtp.onData = function(stream, session, callback) {
|
||||
//stream.pipe(process.stdout);
|
||||
parser(stream).then(verify).then(done).catch(done);
|
||||
stream.on('end', callback);
|
||||
let server = null;
|
||||
let smtp = null;
|
||||
|
||||
const send = function(message, verify, done) {
|
||||
smtp.onData = function(stream, session, callback) {
|
||||
//stream.pipe(process.stdout);
|
||||
parser(stream)
|
||||
.then(verify)
|
||||
.then(done)
|
||||
.catch(done);
|
||||
stream.on('end', callback);
|
||||
};
|
||||
|
||||
server.send(message, function(err) {
|
||||
if (err) throw err;
|
||||
});
|
||||
};
|
||||
|
||||
before(function(done) {
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // prevent CERT_HAS_EXPIRED errors
|
||||
|
||||
smtp = new smtpServer({ secure: true, authMethods: ['LOGIN'] });
|
||||
smtp.listen(port, function() {
|
||||
smtp.onAuth = function(auth, session, callback) {
|
||||
if (auth.username == 'pooh' && auth.password == 'honey') {
|
||||
callback(null, { user: 'pooh' });
|
||||
} else {
|
||||
return callback(new Error('invalid user / pass'));
|
||||
}
|
||||
};
|
||||
|
||||
server.send(message, function(err) { if (err) throw err; });
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // prevent CERT_HAS_EXPIRED errors
|
||||
|
||||
smtp = new smtpServer({secure: true, authMethods: ["LOGIN"]});
|
||||
smtp.listen(port, function() {
|
||||
smtp.onAuth = function(auth, session, callback) {
|
||||
if (auth.username == "pooh" && auth.password == "honey") {
|
||||
callback(null, {user: "pooh"});
|
||||
} else {
|
||||
return callback(new Error("invalid user / pass"));
|
||||
}
|
||||
}
|
||||
|
||||
server = email.server.connect({port:port, user:"pooh", password:"honey", ssl:true});
|
||||
done();
|
||||
server = email.server.connect({
|
||||
port: port,
|
||||
user: 'pooh',
|
||||
password: 'honey',
|
||||
ssl: true
|
||||
});
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
smtp.close(done);
|
||||
});
|
||||
after(function(done) {
|
||||
smtp.close(done);
|
||||
});
|
||||
|
||||
it("simple text message", function(done)
|
||||
{
|
||||
var message = {
|
||||
subject: "this is a test TEXT message from emailjs",
|
||||
from: "zelda@gmail.com",
|
||||
to: "gannon@gmail.com",
|
||||
text: "hello friend, i hope this message finds you well.",
|
||||
"message-id": "this is a special id"
|
||||
};
|
||||
it('simple text message', function(done) {
|
||||
var message = {
|
||||
subject: 'this is a test TEXT message from emailjs',
|
||||
from: 'zelda@gmail.com',
|
||||
to: 'gannon@gmail.com',
|
||||
text: 'hello friend, i hope this message finds you well.',
|
||||
'message-id': 'this is a special id'
|
||||
};
|
||||
|
||||
send(email.message.create(message), function(mail) {
|
||||
expect(mail.text).to.equal(message.text + "\n\n\n");
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
expect(mail.messageId).to.equal('<' + message['message-id'] + '>');
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
email.message.create(message),
|
||||
function(mail) {
|
||||
expect(mail.text).to.equal(message.text + '\n\n\n');
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
expect(mail.messageId).to.equal('<' + message['message-id'] + '>');
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it('null text', function(done) {
|
||||
send({
|
||||
subject: "this is a test TEXT message from emailjs",
|
||||
from: "zelda@gmail.com",
|
||||
to: "gannon@gmail.com",
|
||||
text: null,
|
||||
"message-id": "this is a special id"
|
||||
}, function(mail) {
|
||||
expect(mail.text).to.equal("\n\n\n");
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('empty text', function(done) {
|
||||
send({
|
||||
subject: "this is a test TEXT message from emailjs",
|
||||
from: "zelda@gmail.com",
|
||||
to: "gannon@gmail.com",
|
||||
text: "",
|
||||
"message-id": "this is a special id"
|
||||
}, function(mail) {
|
||||
expect(mail.text).to.equal("\n\n\n");
|
||||
}, done);
|
||||
});
|
||||
|
||||
it("simple unicode text message", function(done)
|
||||
{
|
||||
var message =
|
||||
it('null text', function(done) {
|
||||
send(
|
||||
{
|
||||
subject: "this ✓ is a test ✓ TEXT message from emailjs",
|
||||
from: "zelda✓ <zelda@gmail.com>",
|
||||
to: "gannon✓ <gannon@gmail.com>",
|
||||
text: "hello ✓ friend, i hope this message finds you well."
|
||||
};
|
||||
subject: 'this is a test TEXT message from emailjs',
|
||||
from: 'zelda@gmail.com',
|
||||
to: 'gannon@gmail.com',
|
||||
text: null,
|
||||
'message-id': 'this is a special id'
|
||||
},
|
||||
function(mail) {
|
||||
expect(mail.text).to.equal('\n\n\n');
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
send(email.message.create(message), function(mail)
|
||||
it('empty text', function(done) {
|
||||
send(
|
||||
{
|
||||
expect(mail.text).to.equal(message.text + "\n\n\n");
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
}, done);
|
||||
});
|
||||
subject: 'this is a test TEXT message from emailjs',
|
||||
from: 'zelda@gmail.com',
|
||||
to: 'gannon@gmail.com',
|
||||
text: '',
|
||||
'message-id': 'this is a special id'
|
||||
},
|
||||
function(mail) {
|
||||
expect(mail.text).to.equal('\n\n\n');
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("very large text message", function(done) {
|
||||
this.timeout(20000);
|
||||
// thanks to jart+loberstech for this one!
|
||||
var message = {
|
||||
subject: "this is a test TEXT message from emailjs",
|
||||
from: "ninjas@gmail.com",
|
||||
to: "pirates@gmail.com",
|
||||
text: fs.readFileSync(path.join(__dirname, "attachments/smtp.txt"), "utf-8")
|
||||
};
|
||||
it('simple unicode text message', function(done) {
|
||||
var message = {
|
||||
subject: 'this ✓ is a test ✓ TEXT message from emailjs',
|
||||
from: 'zelda✓ <zelda@gmail.com>',
|
||||
to: 'gannon✓ <gannon@gmail.com>',
|
||||
text: 'hello ✓ friend, i hope this message finds you well.'
|
||||
};
|
||||
|
||||
send(email.message.create(message), function(mail) {
|
||||
expect(mail.text).to.equal(message.text + "\n\n\n");
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
email.message.create(message),
|
||||
function(mail) {
|
||||
expect(mail.text).to.equal(message.text + '\n\n\n');
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("very large text data", function(done) {
|
||||
this.timeout(10000);
|
||||
var text = "<html><body><pre>" + fs.readFileSync(path.join(__dirname, "attachments/smtp.txt"), "utf-8") + "</pre></body></html>";
|
||||
var message = {
|
||||
subject: "this is a test TEXT+DATA message from emailjs",
|
||||
from: "lobsters@gmail.com",
|
||||
to: "lizards@gmail.com",
|
||||
text: "hello friend if you are seeing this, you can not view html emails. it is attached inline.",
|
||||
attachment: {data:text, alternative:true}
|
||||
};
|
||||
it('very large text message', function(done) {
|
||||
this.timeout(20000);
|
||||
// thanks to jart+loberstech for this one!
|
||||
var message = {
|
||||
subject: 'this is a test TEXT message from emailjs',
|
||||
from: 'ninjas@gmail.com',
|
||||
to: 'pirates@gmail.com',
|
||||
text: fs.readFileSync(
|
||||
path.join(__dirname, 'attachments/smtp.txt'),
|
||||
'utf-8'
|
||||
)
|
||||
};
|
||||
|
||||
send(message, function(mail) {
|
||||
expect(mail.html).to.equal(text);
|
||||
expect(mail.text).to.equal(message.text + "\n");
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
email.message.create(message),
|
||||
function(mail) {
|
||||
expect(mail.text).to.equal(message.text + '\n\n\n');
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("html data", function(done)
|
||||
{
|
||||
var html = fs.readFileSync(path.join(__dirname, "attachments/smtp.html"), "utf-8");
|
||||
var message = {
|
||||
subject: "this is a test TEXT+HTML+DATA message from emailjs",
|
||||
from: "obama@gmail.com",
|
||||
to: "mitt@gmail.com",
|
||||
attachment: {data:html, alternative:true}
|
||||
};
|
||||
it('very large text data', function(done) {
|
||||
this.timeout(10000);
|
||||
var text =
|
||||
'<html><body><pre>' +
|
||||
fs.readFileSync(path.join(__dirname, 'attachments/smtp.txt'), 'utf-8') +
|
||||
'</pre></body></html>';
|
||||
var message = {
|
||||
subject: 'this is a test TEXT+DATA message from emailjs',
|
||||
from: 'lobsters@gmail.com',
|
||||
to: 'lizards@gmail.com',
|
||||
text:
|
||||
'hello friend if you are seeing this, you can not view html emails. it is attached inline.',
|
||||
attachment: { data: text, alternative: true }
|
||||
};
|
||||
|
||||
send(message, function(mail) {
|
||||
expect(mail.html).to.equal(html);
|
||||
expect(mail.text).to.equal("\n");
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
message,
|
||||
function(mail) {
|
||||
expect(mail.html).to.equal(text);
|
||||
expect(mail.text).to.equal(message.text + '\n');
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("html file", function(done) {
|
||||
var html = fs.readFileSync(path.join(__dirname, "attachments/smtp.html"), "utf-8");
|
||||
var headers = {
|
||||
subject: "this is a test TEXT+HTML+FILE message from emailjs",
|
||||
from: "thomas@gmail.com",
|
||||
to: "nikolas@gmail.com",
|
||||
attachment: {path:path.join(__dirname, "attachments/smtp.html"), alternative:true}
|
||||
};
|
||||
it('html data', function(done) {
|
||||
var html = fs.readFileSync(
|
||||
path.join(__dirname, 'attachments/smtp.html'),
|
||||
'utf-8'
|
||||
);
|
||||
var message = {
|
||||
subject: 'this is a test TEXT+HTML+DATA message from emailjs',
|
||||
from: 'obama@gmail.com',
|
||||
to: 'mitt@gmail.com',
|
||||
attachment: { data: html, alternative: true }
|
||||
};
|
||||
|
||||
send(headers, function(mail) {
|
||||
expect(mail.html).to.equal(html);
|
||||
expect(mail.text).to.equal("\n");
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
message,
|
||||
function(mail) {
|
||||
expect(mail.html).to.equal(html);
|
||||
expect(mail.text).to.equal('\n');
|
||||
expect(mail.subject).to.equal(message.subject);
|
||||
expect(mail.from.text).to.equal(message.from);
|
||||
expect(mail.to.text).to.equal(message.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("html with image embed", function(done) {
|
||||
var html = fs.readFileSync(path.join(__dirname, "attachments/smtp2.html"), "utf-8");
|
||||
var image = fs.readFileSync(path.join(__dirname, "attachments/smtp.gif"));
|
||||
var headers = {
|
||||
subject: "this is a test TEXT+HTML+IMAGE message from emailjs",
|
||||
from: "ninja@gmail.com",
|
||||
to: "pirate@gmail.com",
|
||||
attachment: {
|
||||
path: path.join(__dirname, "attachments/smtp2.html"),
|
||||
alternative: true,
|
||||
related: [{
|
||||
path: path.join(__dirname, "attachments/smtp.gif"),
|
||||
type: "image/gif",
|
||||
name: "smtp-diagram.gif",
|
||||
headers: {"Content-ID":"<smtp-diagram@local>"}
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
it('html file', function(done) {
|
||||
var html = fs.readFileSync(
|
||||
path.join(__dirname, 'attachments/smtp.html'),
|
||||
'utf-8'
|
||||
);
|
||||
var headers = {
|
||||
subject: 'this is a test TEXT+HTML+FILE message from emailjs',
|
||||
from: 'thomas@gmail.com',
|
||||
to: 'nikolas@gmail.com',
|
||||
attachment: {
|
||||
path: path.join(__dirname, 'attachments/smtp.html'),
|
||||
alternative: true
|
||||
}
|
||||
};
|
||||
|
||||
send(headers, function(mail) {
|
||||
expect(mail.attachments[0].content.toString("base64")).to.equal(image.toString("base64"));
|
||||
expect(mail.html).to.equal(html);
|
||||
expect(mail.text).to.equal("\n");
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
headers,
|
||||
function(mail) {
|
||||
expect(mail.html).to.equal(html);
|
||||
expect(mail.text).to.equal('\n');
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("html data and attachment", function(done) {
|
||||
var html = fs.readFileSync(path.join(__dirname, "attachments/smtp.html"), "utf-8");
|
||||
var headers = {
|
||||
subject: "this is a test TEXT+HTML+FILE message from emailjs",
|
||||
from: "thomas@gmail.com",
|
||||
to: "nikolas@gmail.com",
|
||||
attachment: [
|
||||
{path:path.join(__dirname, "attachments/smtp.html"), alternative:true},
|
||||
{path:path.join(__dirname, "attachments/smtp.gif")}
|
||||
]
|
||||
};
|
||||
it('html with image embed', function(done) {
|
||||
var html = fs.readFileSync(
|
||||
path.join(__dirname, 'attachments/smtp2.html'),
|
||||
'utf-8'
|
||||
);
|
||||
var image = fs.readFileSync(path.join(__dirname, 'attachments/smtp.gif'));
|
||||
var headers = {
|
||||
subject: 'this is a test TEXT+HTML+IMAGE message from emailjs',
|
||||
from: 'ninja@gmail.com',
|
||||
to: 'pirate@gmail.com',
|
||||
attachment: {
|
||||
path: path.join(__dirname, 'attachments/smtp2.html'),
|
||||
alternative: true,
|
||||
related: [
|
||||
{
|
||||
path: path.join(__dirname, 'attachments/smtp.gif'),
|
||||
type: 'image/gif',
|
||||
name: 'smtp-diagram.gif',
|
||||
headers: { 'Content-ID': '<smtp-diagram@local>' }
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
send(headers, function(mail) {
|
||||
expect(mail.html).to.equal(html);
|
||||
expect(mail.text).to.equal("\n");
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
headers,
|
||||
function(mail) {
|
||||
expect(mail.attachments[0].content.toString('base64')).to.equal(
|
||||
image.toString('base64')
|
||||
);
|
||||
expect(mail.html).to.equal(html);
|
||||
expect(mail.text).to.equal('\n');
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("attachment", function(done)
|
||||
{
|
||||
var pdf = fs.readFileSync(path.join(__dirname, "attachments/smtp.pdf"));
|
||||
var headers = {
|
||||
subject: "this is a test TEXT+ATTACHMENT message from emailjs",
|
||||
from: "washing@gmail.com",
|
||||
to: "lincoln@gmail.com",
|
||||
text: "hello friend, i hope this message and pdf finds you well.",
|
||||
attachment:{path:path.join(__dirname, "attachments/smtp.pdf"), type:"application/pdf", name:"smtp-info.pdf"}
|
||||
};
|
||||
it('html data and attachment', function(done) {
|
||||
var html = fs.readFileSync(
|
||||
path.join(__dirname, 'attachments/smtp.html'),
|
||||
'utf-8'
|
||||
);
|
||||
var headers = {
|
||||
subject: 'this is a test TEXT+HTML+FILE message from emailjs',
|
||||
from: 'thomas@gmail.com',
|
||||
to: 'nikolas@gmail.com',
|
||||
attachment: [
|
||||
{
|
||||
path: path.join(__dirname, 'attachments/smtp.html'),
|
||||
alternative: true
|
||||
},
|
||||
{ path: path.join(__dirname, 'attachments/smtp.gif') }
|
||||
]
|
||||
};
|
||||
|
||||
send(headers, function(mail) {
|
||||
expect(mail.attachments[0].content.toString("base64")).to.equal(pdf.toString("base64"));
|
||||
expect(mail.text).to.equal(headers.text + "\n");
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
headers,
|
||||
function(mail) {
|
||||
expect(mail.html).to.equal(html);
|
||||
expect(mail.text).to.equal('\n');
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("attachment sent with unicode filename", function(done) {
|
||||
var pdf = fs.readFileSync(path.join(__dirname, "attachments/smtp.pdf"));
|
||||
var headers = {
|
||||
subject: "this is a test TEXT+ATTACHMENT message from emailjs",
|
||||
from: "washing@gmail.com",
|
||||
to: "lincoln@gmail.com",
|
||||
text: "hello friend, i hope this message and pdf finds you well.",
|
||||
attachment:{path:path.join(__dirname, "attachments/smtp.pdf"), type:"application/pdf", name:"smtp-✓-info.pdf"}
|
||||
};
|
||||
it('attachment', function(done) {
|
||||
var pdf = fs.readFileSync(path.join(__dirname, 'attachments/smtp.pdf'));
|
||||
var headers = {
|
||||
subject: 'this is a test TEXT+ATTACHMENT message from emailjs',
|
||||
from: 'washing@gmail.com',
|
||||
to: 'lincoln@gmail.com',
|
||||
text: 'hello friend, i hope this message and pdf finds you well.',
|
||||
attachment: {
|
||||
path: path.join(__dirname, 'attachments/smtp.pdf'),
|
||||
type: 'application/pdf',
|
||||
name: 'smtp-info.pdf'
|
||||
}
|
||||
};
|
||||
|
||||
send(headers, function(mail) {
|
||||
expect(mail.attachments[0].content.toString("base64")).to.equal(pdf.toString("base64"));
|
||||
expect(mail.attachments[0].filename).to.equal("smtp-✓-info.pdf");
|
||||
expect(mail.text).to.equal(headers.text + "\n");
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
headers,
|
||||
function(mail) {
|
||||
expect(mail.attachments[0].content.toString('base64')).to.equal(
|
||||
pdf.toString('base64')
|
||||
);
|
||||
expect(mail.text).to.equal(headers.text + '\n');
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("attachments", function(done)
|
||||
{
|
||||
var pdf = fs.readFileSync(path.join(__dirname, "attachments/smtp.pdf"));
|
||||
var tar = fs.readFileSync(path.join(__dirname, "attachments/postfix-2.8.7.tar.gz"));
|
||||
var headers =
|
||||
{
|
||||
subject: "this is a test TEXT+2+ATTACHMENTS message from emailjs",
|
||||
from: "sergey@gmail.com",
|
||||
to: "jobs@gmail.com",
|
||||
text: "hello friend, i hope this message and attachments finds you well.",
|
||||
attachment:
|
||||
[
|
||||
{path:path.join(__dirname, "attachments/smtp.pdf"), type:"application/pdf", name:"smtp-info.pdf"},
|
||||
{path:path.join(__dirname, "attachments/postfix-2.8.7.tar.gz"), type:"application/tar-gz", name:"postfix.source.2.8.7.tar.gz"}
|
||||
]
|
||||
};
|
||||
it('attachment sent with unicode filename', function(done) {
|
||||
var pdf = fs.readFileSync(path.join(__dirname, 'attachments/smtp.pdf'));
|
||||
var headers = {
|
||||
subject: 'this is a test TEXT+ATTACHMENT message from emailjs',
|
||||
from: 'washing@gmail.com',
|
||||
to: 'lincoln@gmail.com',
|
||||
text: 'hello friend, i hope this message and pdf finds you well.',
|
||||
attachment: {
|
||||
path: path.join(__dirname, 'attachments/smtp.pdf'),
|
||||
type: 'application/pdf',
|
||||
name: 'smtp-✓-info.pdf'
|
||||
}
|
||||
};
|
||||
|
||||
send(headers, function(mail) {
|
||||
expect(mail.attachments[0].content.toString("base64")).to.equal(pdf.toString("base64"));
|
||||
expect(mail.attachments[1].content.toString("base64")).to.equal(tar.toString("base64"));
|
||||
expect(mail.text).to.equal(headers.text + "\n");
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
}, done);
|
||||
});
|
||||
send(
|
||||
headers,
|
||||
function(mail) {
|
||||
expect(mail.attachments[0].content.toString('base64')).to.equal(
|
||||
pdf.toString('base64')
|
||||
);
|
||||
expect(mail.attachments[0].filename).to.equal('smtp-✓-info.pdf');
|
||||
expect(mail.text).to.equal(headers.text + '\n');
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
it("streams", function(done) {
|
||||
var pdf = fs.readFileSync(path.join(__dirname, "attachments/smtp.pdf"));
|
||||
var tar = fs.readFileSync(path.join(__dirname, "attachments/postfix-2.8.7.tar.gz"));
|
||||
var stream = fs.createReadStream(path.join(__dirname, "attachments/smtp.pdf"));
|
||||
var stream2 = fs.createReadStream(path.join(__dirname, "attachments/postfix-2.8.7.tar.gz"));
|
||||
var headers = {
|
||||
subject: "this is a test TEXT+2+STREAMED+ATTACHMENTS message from emailjs",
|
||||
from: "stanford@gmail.com",
|
||||
to: "mit@gmail.com",
|
||||
text: "hello friend, i hope this message and streamed attachments finds you well.",
|
||||
attachment:
|
||||
[
|
||||
{stream:stream, type:"application/pdf", name:"smtp-info.pdf"},
|
||||
{stream:stream2, type:"application/x-gzip", name:"postfix.source.2.8.7.tar.gz"}
|
||||
]
|
||||
};
|
||||
it('attachments', function(done) {
|
||||
var pdf = fs.readFileSync(path.join(__dirname, 'attachments/smtp.pdf'));
|
||||
var tar = fs.readFileSync(
|
||||
path.join(__dirname, 'attachments/postfix-2.8.7.tar.gz')
|
||||
);
|
||||
var headers = {
|
||||
subject: 'this is a test TEXT+2+ATTACHMENTS message from emailjs',
|
||||
from: 'sergey@gmail.com',
|
||||
to: 'jobs@gmail.com',
|
||||
text: 'hello friend, i hope this message and attachments finds you well.',
|
||||
attachment: [
|
||||
{
|
||||
path: path.join(__dirname, 'attachments/smtp.pdf'),
|
||||
type: 'application/pdf',
|
||||
name: 'smtp-info.pdf'
|
||||
},
|
||||
{
|
||||
path: path.join(__dirname, 'attachments/postfix-2.8.7.tar.gz'),
|
||||
type: 'application/tar-gz',
|
||||
name: 'postfix.source.2.8.7.tar.gz'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
stream.pause();
|
||||
stream2.pause();
|
||||
send(
|
||||
headers,
|
||||
function(mail) {
|
||||
expect(mail.attachments[0].content.toString('base64')).to.equal(
|
||||
pdf.toString('base64')
|
||||
);
|
||||
expect(mail.attachments[1].content.toString('base64')).to.equal(
|
||||
tar.toString('base64')
|
||||
);
|
||||
expect(mail.text).to.equal(headers.text + '\n');
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
|
||||
send(headers, function(mail) {
|
||||
expect(mail.attachments[0].content.toString("base64")).to.equal(pdf.toString("base64"));
|
||||
expect(mail.attachments[1].content.toString("base64")).to.equal(tar.toString("base64"));
|
||||
expect(mail.text).to.equal(headers.text + "\n");
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
}, done);
|
||||
});
|
||||
it('streams', function(done) {
|
||||
var pdf = fs.readFileSync(path.join(__dirname, 'attachments/smtp.pdf'));
|
||||
var tar = fs.readFileSync(
|
||||
path.join(__dirname, 'attachments/postfix-2.8.7.tar.gz')
|
||||
);
|
||||
var stream = fs.createReadStream(
|
||||
path.join(__dirname, 'attachments/smtp.pdf')
|
||||
);
|
||||
var stream2 = fs.createReadStream(
|
||||
path.join(__dirname, 'attachments/postfix-2.8.7.tar.gz')
|
||||
);
|
||||
var headers = {
|
||||
subject:
|
||||
'this is a test TEXT+2+STREAMED+ATTACHMENTS message from emailjs',
|
||||
from: 'stanford@gmail.com',
|
||||
to: 'mit@gmail.com',
|
||||
text:
|
||||
'hello friend, i hope this message and streamed attachments finds you well.',
|
||||
attachment: [
|
||||
{ stream: stream, type: 'application/pdf', name: 'smtp-info.pdf' },
|
||||
{
|
||||
stream: stream2,
|
||||
type: 'application/x-gzip',
|
||||
name: 'postfix.source.2.8.7.tar.gz'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
stream.pause();
|
||||
stream2.pause();
|
||||
|
||||
send(
|
||||
headers,
|
||||
function(mail) {
|
||||
expect(mail.attachments[0].content.toString('base64')).to.equal(
|
||||
pdf.toString('base64')
|
||||
);
|
||||
expect(mail.attachments[1].content.toString('base64')).to.equal(
|
||||
tar.toString('base64')
|
||||
);
|
||||
expect(mail.text).to.equal(headers.text + '\n');
|
||||
expect(mail.subject).to.equal(headers.subject);
|
||||
expect(mail.from.text).to.equal(headers.from);
|
||||
expect(mail.to.text).to.equal(headers.to);
|
||||
},
|
||||
done
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
var path = require('path');
|
||||
var assert = require('assert');
|
||||
const path = require('path');
|
||||
const assert = require('assert');
|
||||
|
||||
describe("Connect to wrong email server", function() {
|
||||
var emailModulePath = require.resolve(path.join(__dirname, '..', 'email'));
|
||||
var email;
|
||||
describe('Connect to wrong email server', function() {
|
||||
const emailModulePath = require.resolve(path.join(__dirname, '..', 'email'));
|
||||
let email;
|
||||
|
||||
beforeEach(function() {
|
||||
if (require.cache[emailModulePath]) {
|
||||
|
@ -12,14 +12,14 @@ describe("Connect to wrong email server", function() {
|
|||
email = require('../email');
|
||||
});
|
||||
|
||||
it("Should not call callback multiple times with wrong server configuration", function(done) {
|
||||
it('Should not call callback multiple times with wrong server configuration', function(done) {
|
||||
this.timeout(5000);
|
||||
var server = email.server.connect({ host: "bar.baz" });
|
||||
const server = email.server.connect({ host: 'bar.baz' });
|
||||
server.send({
|
||||
from: "foo@bar.baz",
|
||||
to: "foo@bar.baz",
|
||||
subject: "hello world",
|
||||
text: "hello world",
|
||||
from: 'foo@bar.baz',
|
||||
to: 'foo@bar.baz',
|
||||
subject: 'hello world',
|
||||
text: 'hello world',
|
||||
}, function(err) {
|
||||
assert.notEqual(err, null);
|
||||
done();
|
||||
|
|
Loading…
Reference in New Issue