2011-09-25 21:51:29 +00:00
|
|
|
var smtp = require('./smtp');
|
|
|
|
var smtpError = require('./error');
|
|
|
|
var message = require('./message');
|
|
|
|
var address = require('./address');
|
2011-02-23 21:23:37 +00:00
|
|
|
|
|
|
|
var Client = function(server)
|
|
|
|
{
|
2011-09-25 21:51:29 +00:00
|
|
|
this.smtp = new smtp.SMTP(server);
|
|
|
|
//this.smtp.debug(1);
|
2011-02-23 21:23:37 +00:00
|
|
|
|
2011-11-11 17:00:08 +00:00
|
|
|
this.queue = [];
|
|
|
|
this.timer = null;
|
2011-09-25 21:51:29 +00:00
|
|
|
this.sending = false;
|
2011-11-11 17:00:08 +00:00
|
|
|
this.ready = false;
|
2011-02-23 21:23:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Client.prototype =
|
|
|
|
{
|
2011-09-25 21:51:29 +00:00
|
|
|
_poll: function()
|
|
|
|
{
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
clearTimeout(self.timer);
|
|
|
|
|
|
|
|
if(self.queue.length)
|
|
|
|
{
|
|
|
|
if(self.smtp.state() == smtp.state.NOTCONNECTED)
|
|
|
|
self._connect(self.queue[0]);
|
|
|
|
|
2011-11-11 17:00:08 +00:00
|
|
|
else if(self.smtp.state() == smtp.state.CONNECTED && !self.sending && self.ready)
|
2011-09-25 21:51:29 +00:00
|
|
|
self._sendmail(self.queue.shift());
|
|
|
|
}
|
2011-12-09 10:23:17 +00:00
|
|
|
// 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)
|
2011-09-25 21:51:29 +00:00
|
|
|
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)
|
2011-11-11 17:00:08 +00:00
|
|
|
{
|
|
|
|
self.ready = true;
|
2011-09-25 21:51:29 +00:00
|
|
|
self._poll();
|
2011-11-11 17:00:08 +00:00
|
|
|
}
|
2011-09-25 21:51:29 +00:00
|
|
|
else
|
|
|
|
stack.callback(err, stack.message);
|
|
|
|
};
|
|
|
|
|
|
|
|
if(!self.smtp.authorized())
|
|
|
|
self.smtp.login(begin);
|
|
|
|
|
|
|
|
else
|
|
|
|
self.smtp.ehlo_or_helo_if_needed(begin);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
stack.callback(err, stack.message);
|
|
|
|
};
|
|
|
|
|
2011-11-11 17:00:08 +00:00
|
|
|
self.ready = false;
|
2011-09-25 21:51:29 +00:00
|
|
|
self.smtp.connect(connect);
|
|
|
|
},
|
|
|
|
|
|
|
|
send: function(msg, callback)
|
|
|
|
{
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
if(!(msg instanceof message.Message) && msg.from && msg.to && msg.text)
|
|
|
|
msg = message.create(msg);
|
|
|
|
|
|
|
|
if(msg instanceof message.Message)
|
|
|
|
{
|
|
|
|
msg.valid(function(valid, why)
|
|
|
|
{
|
|
|
|
if(valid)
|
|
|
|
{
|
|
|
|
var stack =
|
|
|
|
{
|
|
|
|
message: msg,
|
|
|
|
to: address.parse(msg.header.to),
|
|
|
|
from: address.parse(msg.header.from)[0].address,
|
|
|
|
callback: callback || function() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
if(msg.header.cc)
|
|
|
|
stack.to = stack.to.concat(address.parse(msg.header.cc));
|
|
|
|
|
|
|
|
if(msg.header.bcc)
|
|
|
|
stack.to = stack.to.concat(address.parse(msg.header.bcc));
|
|
|
|
|
|
|
|
self.queue.push(stack);
|
|
|
|
self._poll();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
callback({code:-1, message:why}, msg);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else
|
|
|
|
callback({code:-1, message:"message is not a valid Message instance"}, 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
|
2012-05-28 09:59:31 +00:00
|
|
|
self.smtp.rset(function() { self._senddone(err, stack); });
|
2011-09-25 21:51:29 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
return check;
|
|
|
|
},
|
|
|
|
|
|
|
|
_sendmail: function(stack)
|
|
|
|
{
|
|
|
|
var self = this;
|
|
|
|
self.sending = true;
|
|
|
|
self.smtp.mail(self._sendsmtp(stack, self._sendrcpt), '<' + stack.from + '>');
|
|
|
|
},
|
|
|
|
|
|
|
|
_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 +'>');
|
|
|
|
},
|
|
|
|
|
|
|
|
_senddata: function(stack)
|
|
|
|
{
|
|
|
|
var self = this;
|
|
|
|
self.smtp.data(self._sendsmtp(stack, self._sendmessage));
|
|
|
|
},
|
|
|
|
|
|
|
|
_sendmessage: function(stack)
|
|
|
|
{
|
|
|
|
var self = this, stream = stack.message.stream();
|
|
|
|
|
|
|
|
stream.on('data', function(data) { self.smtp.message(data); });
|
2011-12-09 10:23:17 +00:00
|
|
|
stream.on('end', function() { self.smtp.data_end(self._sendsmtp(stack, function() { self._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', function(err) { self.smtp.close(); self._senddone(err, stack); });
|
2011-09-25 21:51:29 +00:00
|
|
|
},
|
|
|
|
|
2011-12-09 10:23:17 +00:00
|
|
|
_senddone: function(err, stack)
|
2011-09-25 21:51:29 +00:00
|
|
|
{
|
|
|
|
var self = this;
|
|
|
|
self.sending = false;
|
|
|
|
stack.callback(err, stack.message);
|
|
|
|
self._poll();
|
|
|
|
}
|
2011-02-23 21:23:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.Client = Client;
|
|
|
|
|
|
|
|
exports.connect = function(server)
|
|
|
|
{
|
2011-09-25 21:51:29 +00:00
|
|
|
return new Client(server);
|
2011-06-06 03:23:04 +00:00
|
|
|
};
|