smtp-server
Advanced tools
Comparing version 1.10.0 to 1.11.0
# Changelog | ||
## v1.11.0 2016-07-07 | ||
* Added support for LMTP protocol. Set `lmtp` option to `true` in order to use it | ||
## v1.10.0 2016-07-06 | ||
@@ -4,0 +8,0 @@ |
@@ -110,3 +110,3 @@ 'use strict'; | ||
if (this._server.options.maxClients && this._server.connections.size > this._server.options.maxClients) { | ||
this.send(421, this.name + ' Too many connected clients, try again in a moment'); | ||
return this.send(421, this.name + ' Too many connected clients, try again in a moment'); | ||
} | ||
@@ -142,3 +142,3 @@ | ||
this._server.logger.info('[%s] Connection from %s', this._id, this.clientHostname); | ||
this.send(220, this.name + ' ESMTP' + (this._server.options.banner ? ' ' + this._server.options.banner : '')); | ||
this.send(220, this.name + ' ' + (this._server.options.lmtp ? 'LMTP' : 'ESMTP') + (this._server.options.banner ? ' ' + this._server.options.banner : '')); | ||
if (typeof next === 'function') { | ||
@@ -295,3 +295,3 @@ next(); | ||
// block spammers that send payloads before server greeting | ||
this.send(421, this.name + ' You talk too soon'); | ||
return this.send(421, this.name + ' You talk too soon'); | ||
} | ||
@@ -302,3 +302,3 @@ } | ||
if (/^(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT) \/.* HTTP\/\d\.\d$/i.test(command)) { | ||
this.send(421, 'HTTP requests not allowed'); | ||
return this.send(421, 'HTTP requests not allowed'); | ||
} | ||
@@ -320,2 +320,13 @@ | ||
commandName = (command || '').toString().split(' ').shift().toUpperCase(); | ||
if (this._server.options.lmtp) { | ||
switch (commandName) { | ||
case 'HELO': | ||
case 'EHLO': | ||
this.send(500, 'Error: ' + commandName + ' not allowed in LMTP server'); | ||
return setImmediate(callback); | ||
case 'LHLO': | ||
commandName = 'EHLO'; | ||
break; | ||
} | ||
} | ||
if (this._isSupported(commandName)) { | ||
@@ -330,3 +341,3 @@ handler = this['handler_' + commandName]; | ||
if (this._unrecognizedCommands >= 10) { | ||
this.send(421, 'Error: too many unrecognized commands'); | ||
return this.send(421, 'Error: too many unrecognized commands'); | ||
} | ||
@@ -342,3 +353,3 @@ | ||
if (this._unauthenticatedCommands >= 10) { | ||
this.send(421, 'Error: too many unauthenticated commands'); | ||
return this.send(421, 'Error: too many unauthenticated commands'); | ||
} | ||
@@ -348,3 +359,3 @@ } | ||
if (!this.hostNameAppearsAs && commandName && ['MAIL', 'RCPT', 'DATA', 'AUTH'].indexOf(commandName) >= 0) { | ||
this.send(503, 'Error: send HELO/EHLO first'); | ||
this.send(503, 'Error: send ' + (this._server.options.lmtp ? 'LHLO' : 'HELO/EHLO') + ' first'); | ||
return setImmediate(callback); | ||
@@ -472,3 +483,3 @@ } | ||
if (parts.length !== 2) { | ||
this.send(501, 'Error: syntax: EHLO hostname'); | ||
this.send(501, 'Error: syntax: ' + (this._server.options.lmtp ? 'LHLO' : 'EHLO') + ' hostname'); | ||
return callback(); | ||
@@ -506,3 +517,3 @@ } | ||
this._resetSession(); // EHLO is effectively the same as RSET | ||
this.send(250, ['OK: Nice to meet you ' + this.clientHostname].concat(features || [])); | ||
this.send(250, [this.name + ' Nice to meet you, ' + this.clientHostname].concat(features || [])); | ||
@@ -527,3 +538,3 @@ callback(); | ||
this._resetSession(); // HELO is effectively the same as RSET | ||
this.send(250, 'OK: Nice to meet you ' + this.clientHostname); | ||
this.send(250, this.name + ' Nice to meet you, ' + this.clientHostname); | ||
@@ -692,3 +703,3 @@ callback(); | ||
// success | ||
this.send(220, this.name + ' ESMTP' + (this._server.options.banner ? ' ' + this._server.options.banner : '')); | ||
this.send(220, this.name + ' ' + (this._server.options.lmtp ? 'LMTP' : 'ESMTP') + (this._server.options.banner ? ' ' + this._server.options.banner : '')); | ||
callback(); | ||
@@ -963,2 +974,4 @@ }; | ||
var close = function (err, message) { | ||
var i, len; | ||
this._server.logger.debug('[%s] C: <%s bytes of DATA>', this._id, this._parser.dataBytes); | ||
@@ -971,4 +984,27 @@ | ||
if (err) { | ||
this.send(err.responseCode || 450, err.message); | ||
if (this._server.options.lmtp) { | ||
// separate error response for every recipient when using LMTP | ||
for (i = 0, len = this.session.envelope.rcptTo.length; i < len; i++) { | ||
this.send(err.responseCode || 450, err.message); | ||
} | ||
} else { | ||
// single error response when using SMTP | ||
this.send(err.responseCode || 450, err.message); | ||
} | ||
} else if (Array.isArray(message)) { | ||
// separate responses for every recipient when using LMTP | ||
message.forEach(function (response) { | ||
if (/Error\]$/i.test(Object.prototype.toString.call(response))) { | ||
this.send(response.responseCode || 450, response.message); | ||
} else { | ||
this.send(250, typeof response === 'string' ? response : 'OK: message accepted'); | ||
} | ||
}.bind(this)); | ||
} else if (this._server.options.lmtp) { | ||
// separate success response for every recipient when using LMTP | ||
for (i = 0, len = this.session.envelope.rcptTo.length; i < len; i++) { | ||
this.send(250, typeof message === 'string' ? message : 'OK: message accepted'); | ||
} | ||
} else { | ||
// single success response when using SMTP | ||
this.send(250, typeof message === 'string' ? message : 'OK: message queued'); | ||
@@ -975,0 +1011,0 @@ } |
@@ -209,4 +209,5 @@ 'use strict'; | ||
this.logger.info( | ||
'%sSMTP Server listening on %s:%s', | ||
'%s%s Server listening on %s:%s', | ||
this.options.secure ? 'Secure ' : '', | ||
this.options.lmtp ? 'LMTP' : 'SMTP', | ||
address.family === 'IPv4' ? address.address : '[' + address.address + ']', | ||
@@ -222,3 +223,3 @@ address.port); | ||
SMTPServer.prototype._onClose = function () { | ||
this.logger.info('SMTP Server closed'); | ||
this.logger.info((this.options.lmtp ? 'LMTP' : 'SMTP') + ' Server closed'); | ||
this.emit('close'); | ||
@@ -225,0 +226,0 @@ }; |
{ | ||
"name": "smtp-server", | ||
"version": "1.10.0", | ||
"version": "1.11.0", | ||
"description": "Create custom SMTP servers on the fly", | ||
"main": "lib/smtp-server.js", | ||
"scripts": { | ||
"test": "grunt" | ||
"test": "grunt mochaTest" | ||
}, | ||
@@ -13,3 +13,3 @@ "author": "Andris Reinman", | ||
"ipv6-normalize": "^1.0.1", | ||
"nodemailer-shared": "^1.0.4" | ||
"nodemailer-shared": "^1.0.5" | ||
}, | ||
@@ -19,6 +19,7 @@ "devDependencies": { | ||
"grunt": "^1.0.1", | ||
"grunt-eslint": "^18.1.0", | ||
"grunt-cli": "^1.2.0", | ||
"grunt-eslint": "^19.0.0", | ||
"grunt-mocha-test": "^0.12.7", | ||
"mocha": "^2.4.5", | ||
"smtp-connection": "^2.3.2" | ||
"mocha": "^2.5.3", | ||
"smtp-connection": "^2.7.0" | ||
}, | ||
@@ -25,0 +26,0 @@ "engines": { |
# smtp-server | ||
Create SMTP server instances on the fly. This is not a full-blown server application like [Haraka](https://haraka.github.io/) but an easy way to add custom SMTP listeners to your app. This module is the successor for the server part of the (now deprecated) SMTP module [simplesmtp](https://www.npmjs.com/package/simplesmtp). For matching SMTP client see [smtp-connection](https://www.npmjs.com/package/smtp-connection). | ||
Create SMTP and LMTP server instances on the fly. This is not a full-blown server application like [Haraka](https://haraka.github.io/) but an easy way to add custom SMTP listeners to your app. This module is the successor for the server part of the (now deprecated) SMTP module [simplesmtp](https://www.npmjs.com/package/simplesmtp). For matching SMTP client see [smtp-connection](https://www.npmjs.com/package/smtp-connection). | ||
@@ -51,2 +51,3 @@ [![Build Status](https://secure.travis-ci.org/andris9/smtp-server.svg)](http://travis-ci.org/andris9/Nodemailer) | ||
* **options.useXForward** boolean, if set to true, enables usage of [XFORWARD](http://www.postfix.org/XFORWARD_README.html) extension. See `session.xForward` (Map object) for the details provided by the client | ||
* **options.lmtp** boolean, if set to true use LMTP protocol instead of SMTP | ||
* **options.socketTimeout** how many milliseconds of inactivity to allow before disconnecting the client (defaults to 1 minute) | ||
@@ -345,2 +346,35 @@ * **options.closeTimeout** how many millisceonds to wait before disconnecting pending connections once server.close() has been called (defaults to 30 seconds) | ||
## Using LMTP | ||
If `lmtp` option is set to true when starting the server, then LMTP protocol is used instead of SMTP. The main | ||
difference between these two is how multiple recipients are handled. In case of SMTP the message either fails or succeeds | ||
but in LMTP the message might fail and succeed individually for every recipient. | ||
If your LMTP server application does not distinguish between different recipients then you do not need to care about it. | ||
On the other hand if you want to report results separately for every recipient you can do this by providing an array | ||
of responses instead of a single error or success message. The array must contain responses in the same order as in the | ||
envelope rcptTo array. | ||
```javascript | ||
var server = new SMTPServer({ | ||
lmtp: true, | ||
onData: function(stream, session, callback){ | ||
stream.pipe(process.stdout); // print message to console | ||
stream.on('end', function(){ | ||
// reject every other recipient | ||
var response = session.envelope.rcptTo.map(function (rcpt, i) { | ||
if (i % 2) { | ||
return new Error('<' + rcpt.address + '> Not accepted'); | ||
} else { | ||
return '<' + rcpt.address + '> Accepted'; | ||
} | ||
}); | ||
callback(null, response); | ||
}); | ||
} | ||
}); | ||
``` | ||
If you provide a single error by invoking `callback(err)` or single success message `callback(null, 'OK')` like when dealing with SMTP then every recipient gets the same response. | ||
## Session object | ||
@@ -347,0 +381,0 @@ |
Sorry, the diff of this file is not supported yet
139163
17
2935
459
7
Updatednodemailer-shared@^1.0.5