1
0
mirror of https://github.com/eleith/emailjs.git synced 2024-07-03 11:38:50 +00:00
emailjs/smtp/client.js

210 lines
5.7 KiB
JavaScript
Raw Normal View History

var smtp = require('./smtp');
var smtpError = require('./error');
var message = require('./message');
var addressparser= require('addressparser');
2011-02-23 21:23:37 +00:00
var Client = function(server)
{
this.smtp = new smtp.SMTP(server);
//this.smtp.debug(1);
2011-02-23 21:23:37 +00:00
this.queue = [];
this.timer = null;
this.sending = false;
this.ready = false;
2011-02-23 21:23:37 +00:00
};
Client.prototype =
{
_poll: function()
{
var self = this;
clearTimeout(self.timer);
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 {
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();
}
};
self.ready = false;
self.smtp.connect(connect);
},
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);
});
}
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);
}
},
_isAttachmentInlinedHtml: function(attachment) {
return attachment &&
(attachment.data || attachment.path) &&
attachment.alternative === true;
},
_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); });
}
};
return check;
},
_sendmail: function(stack)
{
var self = this;
var from = stack.returnPath || stack.from;
self.sending = true;
self.smtp.mail(self._sendsmtp(stack, self._sendrcpt), '<' + 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); });
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); });
},
_senddone: function(err, stack)
{
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)
{
return new Client(server);
};