mirror of
https://github.com/eleith/emailjs.git
synced 2024-07-05 20:10:37 +00:00
catch smtp errors even when not listening for responses, catch attachment errors if path does not exist
This commit is contained in:
parent
208a97e1d3
commit
dd63d6e77e
253
smtp/client.js
253
smtp/client.js
@ -1,164 +1,169 @@
|
||||
var smtp = require('./smtp');
|
||||
var smtpError = require('./error');
|
||||
var message = require('./message');
|
||||
var address = require('./address');
|
||||
var smtp = require('./smtp');
|
||||
var smtpError = require('./error');
|
||||
var message = require('./message');
|
||||
var address = require('./address');
|
||||
|
||||
var Client = function(server)
|
||||
{
|
||||
this.smtp = new smtp.SMTP(server);
|
||||
this.smtp = new smtp.SMTP(server);
|
||||
|
||||
//this.smtp.debug(1);
|
||||
//this.smtp.debug(1);
|
||||
|
||||
this.queue = [];
|
||||
this.timer = null;
|
||||
this.sending = false;
|
||||
this.queue = [];
|
||||
this.timer = null;
|
||||
this.sending = false;
|
||||
};
|
||||
|
||||
Client.prototype =
|
||||
{
|
||||
_poll: function()
|
||||
{
|
||||
var self = this;
|
||||
_poll: function()
|
||||
{
|
||||
var self = this;
|
||||
|
||||
clearTimeout(self.timer);
|
||||
clearTimeout(self.timer);
|
||||
|
||||
if(self.queue.length)
|
||||
{
|
||||
if(self.smtp.state() == smtp.state.NOTCONNECTED)
|
||||
self._connect(self.queue[0]);
|
||||
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._sendmail(self.queue.shift());
|
||||
}
|
||||
// wait around 1 seconds in case something does come in, otherwise close out SMTP connection
|
||||
else
|
||||
self.timer = setTimeout(function() { self.smtp.quit(); }, 1000);
|
||||
},
|
||||
else if(self.smtp.state() == smtp.state.CONNECTED && !self.sending)
|
||||
self._sendmail(self.queue.shift());
|
||||
}
|
||||
// wait around 1 seconds in case something does come in, otherwise close out SMTP connection
|
||||
else
|
||||
self.timer = setTimeout(function() { self.smtp.quit(); }, 1000);
|
||||
},
|
||||
|
||||
_connect: function(stack)
|
||||
{
|
||||
var self = this,
|
||||
_connect: function(stack)
|
||||
{
|
||||
var self = this,
|
||||
|
||||
connect = function(err)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
var begin = function(err)
|
||||
{
|
||||
if(!err)
|
||||
self._poll();
|
||||
connect = function(err)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
var begin = function(err)
|
||||
{
|
||||
if(!err)
|
||||
self._poll();
|
||||
|
||||
else
|
||||
stack.callback(err, stack.message);
|
||||
};
|
||||
else
|
||||
stack.callback(err, stack.message);
|
||||
};
|
||||
|
||||
if(!self.smtp.authorized())
|
||||
self.smtp.login(begin);
|
||||
if(!self.smtp.authorized())
|
||||
self.smtp.login(begin);
|
||||
|
||||
else
|
||||
self.smtp.ehlo_or_helo_if_needed(begin);
|
||||
}
|
||||
else
|
||||
stack.callback(err, stack.message);
|
||||
};
|
||||
else
|
||||
self.smtp.ehlo_or_helo_if_needed(begin);
|
||||
}
|
||||
else
|
||||
stack.callback(err, stack.message);
|
||||
};
|
||||
|
||||
self.smtp.connect(connect);
|
||||
},
|
||||
self.smtp.connect(connect);
|
||||
},
|
||||
|
||||
send: function(msg, callback)
|
||||
{
|
||||
var self = this;
|
||||
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.from && msg.to && msg.text)
|
||||
msg = message.create(msg);
|
||||
|
||||
if(msg instanceof message.Message && msg.valid())
|
||||
{
|
||||
var stack =
|
||||
{
|
||||
message: msg,
|
||||
to: address.parse(msg.header["to"]),
|
||||
from: address.parse(msg.header["from"])[0].address,
|
||||
callback: callback || function() {}
|
||||
};
|
||||
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.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"]));
|
||||
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:"message is not a valid Message instance"}, msg);
|
||||
},
|
||||
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
|
||||
self.smtp.rset(function()
|
||||
{
|
||||
self._senddone(stack, err);
|
||||
});
|
||||
}
|
||||
};
|
||||
_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(err) { self._senddone(stack, err); });
|
||||
}
|
||||
};
|
||||
|
||||
return check;
|
||||
},
|
||||
return check;
|
||||
},
|
||||
|
||||
_sendmail: function(stack)
|
||||
{
|
||||
var self = this;
|
||||
self.sending = true;
|
||||
self.smtp.mail(self._sendsmtp(stack, self._sendrcpt), '<' + stack.from + '>');
|
||||
},
|
||||
_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 +'>');
|
||||
},
|
||||
_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));
|
||||
},
|
||||
_senddata: function(stack)
|
||||
{
|
||||
var self = this;
|
||||
self.smtp.data(self._sendsmtp(stack, self._sendmessage));
|
||||
},
|
||||
|
||||
_sendmessage: function(stack)
|
||||
{
|
||||
var self = this, stream = stack.message.stream();
|
||||
_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, self._senddone)); });
|
||||
stream.on('error', self._sendsmtp(stack));
|
||||
},
|
||||
stream.on('data', function(data) { self.smtp.message(data); });
|
||||
stream.on('end', function() { self.smtp.data_end(self._sendsmtp(stack, self._senddone)); });
|
||||
stream.on('error', function(err) { self.smtp.data_end(function() { self._senddone(stack, err); }); });
|
||||
},
|
||||
|
||||
_senddone: function(stack, err)
|
||||
{
|
||||
var self = this;
|
||||
_senddone: function(stack, err)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
self.sending = false;
|
||||
stack.callback(err, stack.message);
|
||||
self._poll();
|
||||
}
|
||||
self.sending = false;
|
||||
stack.callback(err, stack.message);
|
||||
self._poll();
|
||||
}
|
||||
};
|
||||
|
||||
exports.Client = Client;
|
||||
|
||||
exports.connect = function(server)
|
||||
{
|
||||
return new Client(server);
|
||||
return new Client(server);
|
||||
};
|
||||
|
510
smtp/message.js
510
smtp/message.js
@ -1,322 +1,346 @@
|
||||
var stream = require('stream');
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var CRLF = "\r\n";
|
||||
var stream = require('stream');
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var os = require('os');
|
||||
var path = require('path');
|
||||
var CRLF = "\r\n";
|
||||
|
||||
var generate_boundary = function()
|
||||
{
|
||||
var text = "";
|
||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+_,-./:=?";
|
||||
var text = "";
|
||||
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+_,-./:=?";
|
||||
|
||||
for(var i=0; i < 69; i++)
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
for(var i=0; i < 69; i++)
|
||||
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||
|
||||
return text;
|
||||
return text;
|
||||
};
|
||||
|
||||
var Message = function(headers)
|
||||
{
|
||||
this.attachments = [];
|
||||
this.html = null;
|
||||
this.header = {"message-id":"<" + (new Date()).getTime() + "." + process.pid + "@" + os.hostname() +">"};
|
||||
this.content = "text/plain; charset=utf-8";
|
||||
this.attachments = [];
|
||||
this.html = null;
|
||||
this.header = {"message-id":"<" + (new Date()).getTime() + "." + process.pid + "@" + os.hostname() +">"};
|
||||
this.content = "text/plain; charset=utf-8";
|
||||
|
||||
for(var header in headers)
|
||||
{
|
||||
// allow user to override default content-type to override charset or send a single non-text message
|
||||
if(/^content-type$/i.test(header))
|
||||
{
|
||||
this.content = headers[header];
|
||||
}
|
||||
else if(header == 'text')
|
||||
{
|
||||
this.text = headers[header];
|
||||
}
|
||||
else
|
||||
{
|
||||
// allow any headers the user wants to set??
|
||||
// if(/cc|bcc|to|from|reply-to|sender|subject|date|message-id/i.test(header))
|
||||
this.header[header.toLowerCase()] = headers[header];
|
||||
}
|
||||
}
|
||||
for(var header in headers)
|
||||
{
|
||||
// allow user to override default content-type to override charset or send a single non-text message
|
||||
if(/^content-type$/i.test(header))
|
||||
{
|
||||
this.content = headers[header];
|
||||
}
|
||||
else if(header == 'text')
|
||||
{
|
||||
this.text = headers[header];
|
||||
}
|
||||
else
|
||||
{
|
||||
// allow any headers the user wants to set??
|
||||
// if(/cc|bcc|to|from|reply-to|sender|subject|date|message-id/i.test(header))
|
||||
this.header[header.toLowerCase()] = headers[header];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Message.prototype =
|
||||
{
|
||||
|
||||
attach: function(path, type, name)
|
||||
{
|
||||
this.attachments.push({path:path, type:type, name:name});
|
||||
return this;
|
||||
},
|
||||
attach: function(path, type, name)
|
||||
{
|
||||
this.attachments.push({path:path, type:type, name:name});
|
||||
return this;
|
||||
},
|
||||
|
||||
attach_alternative: function(html, charset)
|
||||
{
|
||||
this.html = {message:html, charset:charset || "utf-8"};
|
||||
return this;
|
||||
},
|
||||
attach_alternative: function(html, charset)
|
||||
{
|
||||
this.html = {message:html, charset:charset || "utf-8"};
|
||||
return this;
|
||||
},
|
||||
|
||||
valid: function()
|
||||
{
|
||||
if(!this.header["from"])
|
||||
return false;
|
||||
valid: function(callback)
|
||||
{
|
||||
var self = this;
|
||||
|
||||
if(!this.header["to"])
|
||||
return false;
|
||||
if(!self.header.from)
|
||||
{
|
||||
callback(false, "message does not have a valid sender");
|
||||
}
|
||||
if(!self.header.to)
|
||||
{
|
||||
callback(false, "message does not have a valid recipient");
|
||||
}
|
||||
else if(self.attachments.length === 0)
|
||||
{
|
||||
callback(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
var failed = [];
|
||||
|
||||
return true;
|
||||
},
|
||||
self.attachments.forEach(function(attachment, index)
|
||||
{
|
||||
path.exists(attachment.path, function(exists)
|
||||
{
|
||||
if(!exists)
|
||||
failed.push(attachment.path + " does not exist");
|
||||
|
||||
stream: function()
|
||||
{
|
||||
return new MessageStream(this);
|
||||
},
|
||||
if(index + 1 == self.attachments.length)
|
||||
callback(failed.length === 0, failed.join(", "));
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
read: function(callback)
|
||||
{
|
||||
var buffer = "";
|
||||
stream: function()
|
||||
{
|
||||
return new MessageStream(this);
|
||||
},
|
||||
|
||||
var capture = function(data)
|
||||
{
|
||||
buffer += data;
|
||||
};
|
||||
read: function(callback)
|
||||
{
|
||||
var buffer = "";
|
||||
|
||||
var output = function(err)
|
||||
{
|
||||
callback(err, buffer);
|
||||
};
|
||||
var capture = function(data)
|
||||
{
|
||||
buffer += data;
|
||||
};
|
||||
|
||||
var str = this.stream();
|
||||
var output = function(err)
|
||||
{
|
||||
callback(err, buffer);
|
||||
};
|
||||
|
||||
str.on('data', capture);
|
||||
str.on('end', output);
|
||||
str.on('error', output);
|
||||
}
|
||||
var str = this.stream();
|
||||
|
||||
str.on('data', capture);
|
||||
str.on('end', output);
|
||||
str.on('error', output);
|
||||
}
|
||||
};
|
||||
|
||||
var MessageStream = function(message)
|
||||
{
|
||||
var self = this;
|
||||
var self = this;
|
||||
|
||||
stream.Stream.call(self);
|
||||
stream.Stream.call(self);
|
||||
|
||||
self.message = message;
|
||||
self.readable = true;
|
||||
self.resume = null;
|
||||
self.paused = false;
|
||||
self.stopped = false;
|
||||
self.stream = null;
|
||||
self.message = message;
|
||||
self.readable = true;
|
||||
self.resume = null;
|
||||
self.paused = false;
|
||||
self.stopped = false;
|
||||
self.stream = null;
|
||||
|
||||
var output_process = function(next)
|
||||
{
|
||||
var check = function()
|
||||
{
|
||||
if(self.stopped)
|
||||
return;
|
||||
var output_process = function(next)
|
||||
{
|
||||
var check = function()
|
||||
{
|
||||
if(self.stopped)
|
||||
return;
|
||||
|
||||
else if(self.paused)
|
||||
self.resume = next;
|
||||
else if(self.paused)
|
||||
self.resume = next;
|
||||
|
||||
else
|
||||
next();
|
||||
};
|
||||
else
|
||||
next();
|
||||
};
|
||||
|
||||
process.nextTick(check);
|
||||
};
|
||||
process.nextTick(check);
|
||||
};
|
||||
|
||||
var output_mixed = function()
|
||||
{
|
||||
var data = [];
|
||||
var boundary = generate_boundary();
|
||||
var output_mixed = function()
|
||||
{
|
||||
var data = [];
|
||||
var boundary = generate_boundary();
|
||||
|
||||
self.emit('data', ["Content-Type: multipart/mixed; boundary=\"", boundary, "\"", CRLF, CRLF].join(""));
|
||||
output_process(function() { output_message(-1, boundary); });
|
||||
};
|
||||
self.emit('data', ["Content-Type: multipart/mixed; boundary=\"", boundary, "\"", CRLF, CRLF].join(""));
|
||||
output_process(function() { output_message(-1, boundary); });
|
||||
};
|
||||
|
||||
var output_message = function(index, boundary)
|
||||
{
|
||||
var next = function()
|
||||
{
|
||||
output_process(function() { output_message(index + 1, boundary); });
|
||||
};
|
||||
var output_message = function(index, boundary)
|
||||
{
|
||||
var next = function()
|
||||
{
|
||||
output_process(function() { output_message(index + 1, boundary); });
|
||||
};
|
||||
|
||||
if(index < 0)
|
||||
{
|
||||
self.emit('data', ["--", boundary, CRLF].join(""));
|
||||
if(index < 0)
|
||||
{
|
||||
self.emit('data', ["--", boundary, CRLF].join(""));
|
||||
|
||||
if(self.message.html)
|
||||
{
|
||||
output_process(function() { output_alternatives(next); });
|
||||
}
|
||||
else
|
||||
{
|
||||
output_text(next);
|
||||
}
|
||||
}
|
||||
else if(index < self.message.attachments.length)
|
||||
{
|
||||
self.emit('data', ["--", boundary, CRLF].join(""));
|
||||
output_process(function() { output_attachment(self.message.attachments[index], next); });
|
||||
}
|
||||
else
|
||||
{
|
||||
self.emit('data', ["--", boundary, "--", CRLF, CRLF].join(""));
|
||||
self.emit('end');
|
||||
}
|
||||
};
|
||||
if(self.message.html)
|
||||
{
|
||||
output_process(function() { output_alternatives(next); });
|
||||
}
|
||||
else
|
||||
{
|
||||
output_text(next);
|
||||
}
|
||||
}
|
||||
else if(index < self.message.attachments.length)
|
||||
{
|
||||
self.emit('data', ["--", boundary, CRLF].join(""));
|
||||
output_process(function() { output_attachment(self.message.attachments[index], next); });
|
||||
}
|
||||
else
|
||||
{
|
||||
self.emit('data', ["--", boundary, "--", CRLF, CRLF].join(""));
|
||||
self.emit('end');
|
||||
}
|
||||
};
|
||||
|
||||
var output_alternatives = function(next)
|
||||
{
|
||||
var boundary = generate_boundary();
|
||||
var output_alternatives = function(next)
|
||||
{
|
||||
var boundary = generate_boundary();
|
||||
|
||||
self.emit('data', ["Content-Type: multipart/alternative; boundary=\"", boundary, "\"", CRLF, CRLF].join(""));
|
||||
self.emit('data', ["--", boundary, CRLF].join(""));
|
||||
self.emit('data', ["Content-Type: multipart/alternative; boundary=\"", boundary, "\"", CRLF, CRLF].join(""));
|
||||
self.emit('data', ["--", boundary, CRLF].join(""));
|
||||
|
||||
output_text(function(){});
|
||||
output_text(function(){});
|
||||
|
||||
var data = ["--", boundary, CRLF];
|
||||
var data = ["--", boundary, CRLF];
|
||||
|
||||
data = data.concat(["Content-Type:text/html; charset=", self.message.html.charset, CRLF, "Content-Transfer-Encoding: base64", CRLF]);
|
||||
data = data.concat(["Content-Disposition: inline", CRLF, CRLF]);
|
||||
data = data.concat([(new Buffer(self.message.html.message)).toString("base64"), CRLF, CRLF]);
|
||||
data = data.concat(["--", boundary, "--", CRLF, CRLF]);
|
||||
data = data.concat(["Content-Type:text/html; charset=", self.message.html.charset, CRLF, "Content-Transfer-Encoding: base64", CRLF]);
|
||||
data = data.concat(["Content-Disposition: inline", CRLF, CRLF]);
|
||||
data = data.concat([(new Buffer(self.message.html.message)).toString("base64"), CRLF, CRLF]);
|
||||
data = data.concat(["--", boundary, "--", CRLF, CRLF]);
|
||||
|
||||
self.emit('data', data.join(""));
|
||||
next();
|
||||
};
|
||||
self.emit('data', data.join(""));
|
||||
next();
|
||||
};
|
||||
|
||||
var output_attachment = function(attachment, next)
|
||||
{
|
||||
var data = ["Content-Type: ", attachment.type, CRLF, "Content-Transfer-Encoding: base64", CRLF];
|
||||
data = data.concat(["Content-Disposition: attachment; filename=\"", attachment.name, "\"", CRLF, CRLF]);
|
||||
var output_attachment = function(attachment, next)
|
||||
{
|
||||
var data = ["Content-Type: ", attachment.type, CRLF, "Content-Transfer-Encoding: base64", CRLF];
|
||||
data = data.concat(["Content-Disposition: attachment; filename=\"", attachment.name, "\"", CRLF, CRLF]);
|
||||
|
||||
self.emit('data', data.join(""));
|
||||
|
||||
var mimechunk = 76; // MIME standard wants 76 char chunks when sending out
|
||||
var chunk = mimechunk*25*3; // 5700
|
||||
var buffer = new Buffer(chunk);
|
||||
var opened = function(err, fd)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
var read = function(err, bytes)
|
||||
{
|
||||
if(self.paused)
|
||||
{
|
||||
self.resume = function() { read(err, bytes); };
|
||||
}
|
||||
else if(self.stopped)
|
||||
{
|
||||
fs.close(fd);
|
||||
}
|
||||
else if(!err)
|
||||
{
|
||||
var info = buffer.toString("base64", 0, bytes);
|
||||
var leftover= info.length % mimechunk;
|
||||
var loops = Math.round(info.length / mimechunk);
|
||||
self.emit('data', data.join(""));
|
||||
|
||||
var mimechunk = 76; // MIME standard wants 76 char chunks when sending out
|
||||
var chunk = mimechunk*25*3; // 5700
|
||||
var buffer = new Buffer(chunk);
|
||||
var opened = function(err, fd)
|
||||
{
|
||||
if(!err)
|
||||
{
|
||||
var read = function(err, bytes)
|
||||
{
|
||||
if(self.paused)
|
||||
{
|
||||
self.resume = function() { read(err, bytes); };
|
||||
}
|
||||
else if(self.stopped)
|
||||
{
|
||||
fs.close(fd);
|
||||
}
|
||||
else if(!err)
|
||||
{
|
||||
var info = buffer.toString("base64", 0, bytes);
|
||||
var leftover= info.length % mimechunk;
|
||||
var loops = Math.round(info.length / mimechunk);
|
||||
|
||||
for(var step = 0; step < loops; step++)
|
||||
{
|
||||
self.emit('data', info.substring(step*mimechunk, mimechunk*(step + 1)) + CRLF);
|
||||
}
|
||||
for(var step = 0; step < loops; step++)
|
||||
{
|
||||
self.emit('data', info.substring(step*mimechunk, mimechunk*(step + 1)) + CRLF);
|
||||
}
|
||||
|
||||
if(bytes == chunk) // gauranteed no leftovers
|
||||
{
|
||||
fs.read(fd, buffer, 0, chunk, null, read);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.emit('data', leftover ? info.substr(-leftover) + CRLF + CRLF : CRLF); // important!
|
||||
fs.close(fd, next);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fs.close(fd);
|
||||
self.emit('error', err);
|
||||
}
|
||||
};
|
||||
if(bytes == chunk) // gauranteed no leftovers
|
||||
{
|
||||
fs.read(fd, buffer, 0, chunk, null, read);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.emit('data', leftover ? info.substr(-leftover) + CRLF + CRLF : CRLF); // important!
|
||||
fs.close(fd, next);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fs.close(fd);
|
||||
self.emit('error', err);
|
||||
}
|
||||
};
|
||||
|
||||
fs.read(fd, buffer, 0, chunk, null, read);
|
||||
}
|
||||
else
|
||||
self.emit('error', err);
|
||||
};
|
||||
fs.read(fd, buffer, 0, chunk, null, read);
|
||||
}
|
||||
else
|
||||
self.emit('error', err);
|
||||
};
|
||||
|
||||
fs.open(attachment.path, 'r+', opened);
|
||||
};
|
||||
fs.open(attachment.path, 'r+', opened);
|
||||
};
|
||||
|
||||
var output_text = function(next)
|
||||
{
|
||||
var data = ["Content-Type:", self.message.content, CRLF, "Content-Transfer-Encoding: 7bit", CRLF];
|
||||
data = data.concat(["Content-Disposition: inline", CRLF, CRLF]);
|
||||
data = data.concat([self.message.text || "", CRLF, CRLF]);
|
||||
var output_text = function(next)
|
||||
{
|
||||
var data = ["Content-Type:", self.message.content, CRLF, "Content-Transfer-Encoding: 7bit", CRLF];
|
||||
data = data.concat(["Content-Disposition: inline", CRLF, CRLF]);
|
||||
data = data.concat([self.message.text || "", CRLF, CRLF]);
|
||||
|
||||
self.emit('data', data.join(""));
|
||||
next();
|
||||
};
|
||||
self.emit('data', data.join(""));
|
||||
next();
|
||||
};
|
||||
|
||||
var output_data = function()
|
||||
{
|
||||
// are there attachments or alternatives?
|
||||
if(self.message.attachments.length || self.message.html)
|
||||
{
|
||||
self.emit('data', "MIME-Version: 1.0" + CRLF);
|
||||
output_process(output_mixed);
|
||||
}
|
||||
var output_data = function()
|
||||
{
|
||||
// are there attachments or alternatives?
|
||||
if(self.message.attachments.length || self.message.html)
|
||||
{
|
||||
self.emit('data', "MIME-Version: 1.0" + CRLF);
|
||||
output_process(output_mixed);
|
||||
}
|
||||
|
||||
// otherwise, you only have a text message
|
||||
else
|
||||
{
|
||||
output_text(function() { self.emit('end'); });
|
||||
}
|
||||
};
|
||||
// otherwise, you only have a text message
|
||||
else
|
||||
{
|
||||
output_text(function() { self.emit('end'); });
|
||||
}
|
||||
};
|
||||
|
||||
var output_header = function()
|
||||
{
|
||||
var data = [];
|
||||
var output_header = function()
|
||||
{
|
||||
var data = [];
|
||||
|
||||
for(var header in self.message.header)
|
||||
{
|
||||
// do not output BCC in the headers...
|
||||
if(!(/bcc/i.test(header)))
|
||||
data = data.concat([header, ": ", self.message.header[header], CRLF]);
|
||||
}
|
||||
for(var header in self.message.header)
|
||||
{
|
||||
// do not output BCC in the headers...
|
||||
if(!(/bcc/i.test(header)))
|
||||
data = data.concat([header, ": ", self.message.header[header], CRLF]);
|
||||
}
|
||||
|
||||
self.emit('data', data.join(''));
|
||||
output_process(output_data);
|
||||
};
|
||||
self.emit('data', data.join(''));
|
||||
output_process(output_data);
|
||||
};
|
||||
|
||||
output_process(output_header);
|
||||
return;
|
||||
output_process(output_header);
|
||||
return;
|
||||
};
|
||||
|
||||
MessageStream.prototype.pause = function()
|
||||
{
|
||||
self.paused = true;
|
||||
self.paused = true;
|
||||
};
|
||||
|
||||
MessageStream.prototype.resume = function()
|
||||
{
|
||||
self.paused = false;
|
||||
self.paused = false;
|
||||
|
||||
if(self.resume)
|
||||
{
|
||||
var resume = self.resume;
|
||||
self.resume = null;
|
||||
resume();
|
||||
}
|
||||
if(self.resume)
|
||||
{
|
||||
var resume = self.resume;
|
||||
self.resume = null;
|
||||
resume();
|
||||
}
|
||||
};
|
||||
|
||||
MessageStream.prototype.destroy = function()
|
||||
{
|
||||
self.stopped = true;
|
||||
self.stopped = true;
|
||||
};
|
||||
|
||||
MessageStream.prototype.destroySoon = function()
|
||||
{
|
||||
self.stopped = true;
|
||||
self.stopped = true;
|
||||
};
|
||||
|
||||
util.inherits(MessageStream, stream.Stream);
|
||||
@ -324,5 +348,5 @@ util.inherits(MessageStream, stream.Stream);
|
||||
exports.Message = Message;
|
||||
exports.create = function(headers)
|
||||
{
|
||||
return new Message(headers);
|
||||
return new Message(headers);
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
var SMTPError = require('./error');
|
||||
|
||||
function SMTPResponse(stream, timeout)
|
||||
function SMTPResponse(stream, timeout, onerror)
|
||||
{
|
||||
var buffer = '',
|
||||
|
||||
@ -8,7 +8,11 @@ function SMTPResponse(stream, timeout)
|
||||
{
|
||||
if(buffer.length)
|
||||
{
|
||||
stream.emit('response', null, buffer.replace("\r", ''));
|
||||
// parse buffer for response codes
|
||||
var line = buffer.replace("\r", '');
|
||||
var match = line ? line.match(/(\d+)\s?(.*)/) : null;
|
||||
|
||||
stream.emit('response', null, match ? {code:match[1], message:match[2], data:line} : {code:-1, data:line});
|
||||
buffer = '';
|
||||
}
|
||||
},
|
||||
@ -16,21 +20,20 @@ function SMTPResponse(stream, timeout)
|
||||
error = function(err)
|
||||
{
|
||||
stream.emit('response', {code:SMTPError.ERROR, message:"connection encountered an error", error:err});
|
||||
end();
|
||||
destroy(err);
|
||||
},
|
||||
|
||||
timedout = function(err)
|
||||
{
|
||||
stream.emit('response', {code:SMTPError.TIMEDOUT, message:"connection has timedout", error:err});
|
||||
end();
|
||||
},
|
||||
timedout = function(err)
|
||||
{
|
||||
stream.emit('response', {code:SMTPError.TIMEDOUT, message:"timedout while connecting to smtp server", error:err});
|
||||
destroy(err);
|
||||
},
|
||||
|
||||
watch = function(data)
|
||||
{
|
||||
var decoded = data.toString();
|
||||
var emit = false;
|
||||
var code = 0;
|
||||
var parsed = decoded.match(/^(?:.*\n)?([^\n]+)\n\s*$/m);
|
||||
|
||||
buffer += decoded;
|
||||
notify();
|
||||
@ -38,45 +41,36 @@ function SMTPResponse(stream, timeout)
|
||||
|
||||
close = function(err)
|
||||
{
|
||||
if(buffer.length)
|
||||
notify();
|
||||
|
||||
else
|
||||
stream.emit('response', {code:SMTPError.CONNECTIONCLOSED, message:"connection has closed", error:err});
|
||||
|
||||
end();
|
||||
stream.emit('response', {code:SMTPError.CONNECTIONCLOSED, message:"connection has closed", error:err});
|
||||
destroy(err);
|
||||
},
|
||||
|
||||
end = function(err)
|
||||
{
|
||||
if(buffer.length)
|
||||
notify();
|
||||
stream.emit('response', {code:SMTPError.CONNECTIONENDED, message:"connection has ended", error:err});
|
||||
destroy(err);
|
||||
};
|
||||
|
||||
else
|
||||
stream.emit('response', {code:SMTPError.CONNECTIONENDED, message:"connection has ended", error:err});
|
||||
|
||||
stream.removeAllListeners('response');
|
||||
destroy = function()
|
||||
{
|
||||
stream.removeAllListeners('response');
|
||||
stream.removeListener('data', watch);
|
||||
stream.removeListener('end', end);
|
||||
stream.removeListener('close', close);
|
||||
stream.removeListener('error', error);
|
||||
stream.removeListener('timeout', timedout);
|
||||
};
|
||||
|
||||
if(typeof(onerror) == "function")
|
||||
onerror(err);
|
||||
};
|
||||
|
||||
stream.on('data', watch);
|
||||
stream.on('end', end);
|
||||
stream.on('close', close);
|
||||
stream.on('timeout', timedout);
|
||||
stream.on('error', error);
|
||||
stream.setTimeout(timeout, timedout);
|
||||
}
|
||||
|
||||
exports.watch = function(stream)
|
||||
exports.monitor = function(stream)
|
||||
{
|
||||
return new SMTPResponse(stream);
|
||||
};
|
||||
|
||||
exports.parse = function(line)
|
||||
{
|
||||
var match = line ? line.match(/(\d+)\s?(.*)/) : null;
|
||||
return match ? {code:match[1], message:match[2]} : {};
|
||||
}
|
||||
|
1045
smtp/smtp.js
1045
smtp/smtp.js
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user