Permalink
Browse files

move smtp logic from mail to smptclient

  • Loading branch information...
1 parent fbb1d95 commit 5b8fe88ba43e6251ecccff65992e744403abdba7 @bmeck bmeck committed with andris9 Apr 29, 2011
Showing with 134 additions and 98 deletions.
  1. +4 −3 examples/example.js
  2. +10 −90 lib/mail.js
  3. +120 −5 lib/smtp.js
View
@@ -9,9 +9,10 @@ nodemailer.SMTP = {
use_authentication: true,
ssl: true,
user: undefined,
- pass: undefined
+ pass: undefined,
+ debug: true
}
-
+console.log("SMTP Configured")
// unique cid value for the embedded image
var cid = Date.now()+".image.png";
@@ -52,7 +53,7 @@ var callback = function(error, success){
console.log("Message failed, reschedule!");
}
}
-
+console.log("Sending Mail")
// Send the e-mail
process.on("uncaughtException",function(e){console.log("Uncaught Exception",e.stack);})
var mail;
View
@@ -1,4 +1,4 @@
-var SMTPClient = require("./smtp").SMTPClient,
+var SMTPClient = exports.SMTPClient = require("./smtp").SMTPClient,
mimelib = require("./mime"),
exec = require('child_process').exec
util = require("util"),
@@ -444,7 +444,6 @@ EmailMessage.prototype.generateAddresses = function(addresses, limit, use_list){
* and success is true, then the message was sent to the recipients
**/
EmailMessage.prototype.send = function(callback){
-
this.prepareVariables();
var headers = this.generateHeaders(),
@@ -467,103 +466,24 @@ EmailMessage.prototype.send = function(callback){
var mail = this;
// use SERVER
- var smtp = new SMTPClient(this.SERVER.host, this.SERVER.port, {
+ var client = new SMTPClient(this.SERVER.host, this.SERVER.port, {
hostname: this.SERVER.hostname,
use_authentication: this.SERVER.use_authentication,
user: this.SERVER.user,
pass: this.SERVER.pass,
ssl: this.SERVER.ssl,
debug: this.debug
});
- smtp.on("connection_stable", function() {mail.emit.apply(mail,["connection_stable"].concat([].slice.call(arguments)))})
- smtp.on("error", function(error){
+ client.on("empty",function() {
+ client.send("QUIT",function() {
+ client.close();
+ })
+ })
+ client.on("connection_stable", function() {mail.emit.apply(mail,["connection_stable"].concat([].slice.call(arguments)))})
+ client.on("error", function(error){
callback && callback(error, null);
});
- var i = 0;
- //concat if you need to do forwards
- var toAddress = this.toAddress.concat();
- var fromAddress = this.fromAddress;
- function nextSender() {
- if(i === fromAddress.length) {
- i = 0;
- nextRecipient();
- }
- else {
- smtp.send("MAIL FROM:<"+fromAddress[i++]+">", function(error, message) {
- if(error) {
- smtp.close();
- process.nextTick(function(){
- callback && callback(error, null);
- });
- return;
- }
- process.nextTick(nextSender);
- });
- }
- }
- function nextRecipient() {
- if(i === toAddress.length) {
- smtp.send("DATA",function(error, message) {
- process.nextTick(sendBody);
- });
- }
- else {
- var address = toAddress[i++];
- smtp.send("RCPT TO:<"+address+">", function(error, message) {
- if(error) {
- var forwardAddress;
- //Empty addresses are valid (for server sent notifications).
- if(forwardAddress = error.message.match(/^551.*try\s+([<][^>]*[>])/)) {
- mail.emit("forward", address,forwardAddress[1]);
- toAddress.splice(i,0,forwardAddress[1])
- process.nextTick(nextRecipient);
- return;
- }
- //Not all error codes are true failures (we may be able to still send it to other recipients)
- else if(error.message.match(/^(?:552|451|452|500|503|421)/)){
- smtp.close();
- process.nextTick(function(){
- callback && callback(error, null);
- });
- return;
- } else {
- mail.emit("retain", address);
- process.nextTick(nextRecipient);
- return;
- }
- }
-
- if(message && /^251/.test(message.test)) {
- mail.emit("defer",address);
- } else {
- mail.emit("send",address);
- }
- process.nextTick(nextRecipient);
- });
- }
- }
- process.nextTick(nextSender);
-
- // Sends e-mail body to the SMTP server and finishes up
- function sendBody(){
- smtp.send(headers+"\r\n\r\n");
- smtp.send(body);
- smtp.send("\r\n.", function(error, message){
- if(!error){
- smtp.send("QUIT", function(error, message){
- smtp.close();
- process.nextTick(function(){
- callback && callback(null, true);
- });
- });
- }else{
- smtp.close();
- process.nextTick(function(){
- callback && callback(null, false);
- });
- }
- });
- }
+ client.sendMail(mail);
}
/**
View
@@ -95,8 +95,8 @@ function SMTPClient(host, port, options){
this.port = port || (this.options.ssl && 465 || 25);
// defaul hostname is machine hostname or [IP]
- var defaultHostname = ("hostname" in oslib && oslib.hostname()) ||
- ("getHostname" in oslib && oslib.getHostname()) ||
+ var defaultHostname = (oslib.hostname && oslib.hostname()) ||
+ (oslib.getHostname && oslib.getHostname()) ||
"";
if(defaultHostname.indexOf('.')<0){
defaultHostname = "[127.0.0.1]";
@@ -111,6 +111,8 @@ function SMTPClient(host, port, options){
this.debug = !!this.options.debug;
+ this.sending = false;
+ this.logged_in = false; // Used for queueing and flushing
this.remote_pipelining = false; // Is pipelining enabled
this.remote_starttls = false; // Is TLS enabled, currently no effect
this.remote_extended = true; // Does the server support EHLO or HELO
@@ -120,6 +122,7 @@ function SMTPClient(host, port, options){
this._connected = false; // Indicates if an active connection is available
this._connection = false; // Holds connection info
this._callbackQueue = []; // Queues the responses FIFO (needed for pipelining)
+ this._messageQueue = []; // Queues the messages FIFO
this._data_remainder = ""; // Needed to group multi-line messages from server, string buffer to prevent newline issue.
this._timeoutTimer = null;
}
@@ -128,6 +131,111 @@ utillib.inherits(SMTPClient, EventEmitter);
///////////// PUBLIC METHODS /////////////
+SMTPClient.prototype._flushMessages = function() {
+ if(this.sending) return;
+ var smtp = this;
+ var message = this._messageQueue.shift();
+ if(!message) {
+ this.emit("empty");
+ return;
+ }
+ var mail = message.message;
+ var callback = message.callback;
+ this.sending = true;
+ mail.prepareVariables();
+ var headers = mail.generateHeaders(),
+ body = mail.generateBody();
+ var i = 0;
+ //concat if you need to do forwards
+ var toAddress = mail.toAddress.concat();
+ var fromAddress = mail.fromAddress;
+ function nextSender() {
+ if(i === fromAddress.length) {
+ i = 0;
+ nextRecipient();
+ }
+ else {
+ smtp.send("MAIL FROM:<"+fromAddress[i++]+">", function(error, message) {
+ if(error) {
+ smtp.close();
+ process.nextTick(function(){
+ callback && callback(error, null);
+ });
+ return;
+ }
+ process.nextTick(nextSender);
+ });
+ }
+ }
+ function nextRecipient() {
+ if(i === toAddress.length) {
+ smtp.send("DATA",function(error, message) {
+ process.nextTick(sendBody);
+ });
+ }
+ else {
+ var address = toAddress[i++];
+ smtp.send("RCPT TO:<"+address+">", function(error, message) {
+ if(error) {
+ var forwardAddress;
+ //Empty addresses are valid (for server sent notifications).
+ if(forwardAddress = error.message.match(/^551.*try\s+([<][^>]*[>])/)) {
+ mail.emit("forward", address,forwardAddress[1]);
+ toAddress.splice(i,0,forwardAddress[1])
+ process.nextTick(nextRecipient);
+ return;
+ }
+ //Not all error codes are true failures (we may be able to still send it to other recipients)
+ else if(error.message.match(/^(?:552|451|452|500|503|421)/)){
+ smtp.close();
+ process.nextTick(function(){
+ callback && callback(error, null);
+ });
+ return;
+ } else {
+ mail.emit("retain", address);
+ process.nextTick(nextRecipient);
+ return;
+ }
+ }
+
+ if(message && /^251/.test(message.test)) {
+ mail.emit("defer",address);
+ } else {
+ mail.emit("send",address);
+ }
+ process.nextTick(nextRecipient);
+ });
+ }
+ }
+ process.nextTick(nextSender);
+
+ // Sends e-mail body to the SMTP server and finishes up
+ function sendBody(){
+ smtp.send(headers+"\r\n\r\n");
+ smtp.send(body);
+ smtp.send("\r\n.", function(error, message){
+ if(!error){
+ smtp.sending = false;
+ smtp._flushMessages();
+ }else{
+ smtp.close();
+ process.nextTick(function(){
+ callback && callback(null, false);
+ });
+ }
+ });
+ }
+}
+
+SMTPClient.prototype.sendMail = function sendMail(message,callback) {
+ this._messageQueue.push({
+ message:message,
+ callback:callback
+ });
+ if(this._messageQueue.length === 1) this._flushMessages();
+}
+
/**
* smtp.SMTPClient#send(data, callback) -> undefined
* - data (String): text to be sent to the SMTP server
@@ -187,7 +295,7 @@ SMTPClient.prototype.close = function(){
* - callback (Function): function to be run after the server has responded
*
* Sends a string to the server, appends \r\n to the end so this is not
- * meant to send data (mail body) but comands.
+ * meant to send data (mail body) but commands.
**/
SMTPClient.prototype._sendCommand = function(data, callback){
this._callbackQueue.push({callback: callback});
@@ -225,6 +333,7 @@ SMTPClient.prototype._loginHandler = function(callback){
//FIXME: Plaintext AUTH generally needs TSL support, problematic with Node.JS v0.3
if(!this.options.use_authentication){
+ this.logged_in = true;
callback();
}else{
this.send("AUTH PLAIN "+new Buffer(
@@ -237,6 +346,8 @@ SMTPClient.prototype._loginHandler = function(callback){
return;
}
// login success
+ this.logged_in = true;
+ this.emit("auth");
callback();
}).bind(this));
}
@@ -395,11 +506,12 @@ SMTPClient.prototype._handshake = function(callback){
*
* Waits for 10 seconds after connection and if nothing happened emits an error
**/
-SMTPClient.prototype._waitForTimeout = function(){
+SMTPClient.prototype._waitForTimeout = function(time){
+ clearTimeout(this._timeoutTimer);
this._timeoutTimer = setTimeout((function(){
this.emit("error", new Error("Timeout waiting for response from server"));
this.close();
- }).bind(this), 0.1*1000);
+ }).bind(this), time || 10*1000);
}
/**
@@ -468,6 +580,9 @@ SMTPClient.prototype._createConnection = function(callback){
this.close();
}).bind(this));
+ //30 seconds to connect
+ this._waitForTimeout(30 * 1000);
+ //10 seconds for data
this._connection.on("connect", this._waitForTimeout.bind(this));
this._connection.on("data", this._onData = this._onData.bind(this, callback));
}

0 comments on commit 5b8fe88

Please sign in to comment.