Command Injection
Description
A crafted recipient email address can inject arbitrary command flags into the sendmail binary via nodemailer before 6.4.16.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
A crafted recipient email address can inject arbitrary command flags into the sendmail binary via nodemailer before 6.4.16.
Vulnerability
Overview
This vulnerability affects the nodemailer npm package before version 6.4.16. The root cause is insufficient sanitization of recipient email addresses when using the sendmail transport. When constructing the command line for the sendmail binary, the library passes the recipient address directly as an argument without proper filtering, allowing an attacker to inject arbitrary command-line flags. [1][4]
Attack
Vector
An attacker can exploit this by providing a specially crafted email address that starts with a dash (e.g., -bi@example.com). This causes the sendmail binary to interpret the remainder of the string as a command-line flag rather than a recipient address. The attack requires the ability to send emails through the vulnerable application and the use of the sendmail transport. No authentication is needed if the application is configured with sendmail as the transport method. [4]
Impact
Successful exploitation can lead to arbitrary command flag injection in the sendmail process. Depending on the sendmail flags used, this can result in information disclosure, configuration changes, or other unintended behaviors. For example, the -d0.1a flag prints debug information including the compiled version and options, potentially leaking sensitive system details. The -Dfilename flag writes debug output to a file. [4]
Mitigation
The vulnerability is fixed in nodemailer version 6.4.16 and later. Users are strongly advised to upgrade immediately. No workarounds are documented; updating the package is the only effective mitigation. The fix was introduced in commit ba31c64c910d884579875c52d57ac45acc47aa54. [1][4]
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
nodemailernpm | < 6.4.16 | 6.4.16 |
Affected products
1Patches
140 files changed · +662 −677
Gruntfile.js+1 −1 modified@@ -1,6 +1,6 @@ 'use strict'; -module.exports = function(grunt) { +module.exports = function (grunt) { // Project configuration. grunt.initConfig({ eslint: {
lib/dkim/message-parser.js+1 −4 modified@@ -146,10 +146,7 @@ class MessageParser extends Transform { return lines .filter(line => line.trim()) .map(line => ({ - key: line - .substr(0, line.indexOf(':')) - .trim() - .toLowerCase(), + key: line.substr(0, line.indexOf(':')).trim().toLowerCase(), line })); }
lib/fetch/cookies.js+1 −4 modified@@ -110,10 +110,7 @@ class Cookies { .split(';') .forEach(cookiePart => { let valueParts = cookiePart.split('='); - let key = valueParts - .shift() - .trim() - .toLowerCase(); + let key = valueParts.shift().trim().toLowerCase(); let value = valueParts.join('=').trim(); let domain;
lib/fetch/index.js+3 −11 modified@@ -10,7 +10,7 @@ const packageData = require('../../package.json'); const MAX_REDIRECTS = 5; -module.exports = function(url, options) { +module.exports = function (url, options) { return fetch(url, options); }; @@ -33,11 +33,7 @@ function fetch(url, options) { let fetchRes = options.fetchRes; let parsed = urllib.parse(url); - let method = - (options.method || '') - .toString() - .trim() - .toUpperCase() || 'GET'; + let method = (options.method || '').toString().trim().toUpperCase() || 'GET'; let finished = false; let cookies; let body; @@ -115,11 +111,7 @@ function fetch(url, options) { headers['Content-Length'] = body.length; } // if method is not provided, use POST instead of GET - method = - (options.method || '') - .toString() - .trim() - .toUpperCase() || 'POST'; + method = (options.method || '').toString().trim().toUpperCase() || 'POST'; } let req;
lib/mailer/mail-message.js+1 −6 modified@@ -64,12 +64,7 @@ class MailMessage { if (this.data.attachments && this.data.attachments.length) { this.data.attachments.forEach((attachment, i) => { if (!attachment.filename) { - attachment.filename = - (attachment.path || attachment.href || '') - .split('/') - .pop() - .split('?') - .shift() || 'attachment-' + (i + 1); + attachment.filename = (attachment.path || attachment.href || '').split('/').pop().split('?').shift() || 'attachment-' + (i + 1); if (attachment.filename.indexOf('.') < 0) { attachment.filename += '.' + mimeFuncs.detectExtension(attachment.contentType); }
lib/mime-funcs/mime-types.js+2 −9 modified@@ -2063,11 +2063,7 @@ module.exports = { } let parsed = path.parse(filename); - let extension = (parsed.ext.substr(1) || parsed.name || '') - .split('?') - .shift() - .trim() - .toLowerCase(); + let extension = (parsed.ext.substr(1) || parsed.name || '').split('?').shift().trim().toLowerCase(); let value = defaultMimeType; if (extensions.has(extension)) { @@ -2084,10 +2080,7 @@ module.exports = { if (!mimeType) { return defaultExtension; } - let parts = (mimeType || '') - .toLowerCase() - .trim() - .split('/'); + let parts = (mimeType || '').toLowerCase().trim().split('/'); let rootType = parts.shift().trim(); let subType = parts.join('/').trim();
lib/nodemailer.js+4 −9 modified@@ -13,16 +13,11 @@ const packageData = require('../package.json'); const ETHEREAL_API = (process.env.ETHEREAL_API || 'https://api.nodemailer.com').replace(/\/+$/, ''); const ETHEREAL_WEB = (process.env.ETHEREAL_WEB || 'https://ethereal.email').replace(/\/+$/, ''); -const ETHEREAL_CACHE = ['true', 'yes', 'y', '1'].includes( - (process.env.ETHEREAL_CACHE || 'yes') - .toString() - .trim() - .toLowerCase() -); +const ETHEREAL_CACHE = ['true', 'yes', 'y', '1'].includes((process.env.ETHEREAL_CACHE || 'yes').toString().trim().toLowerCase()); let testAccount = false; -module.exports.createTransport = function(transporter, defaults) { +module.exports.createTransport = function (transporter, defaults) { let urlConfig; let options; let mailer; @@ -60,7 +55,7 @@ module.exports.createTransport = function(transporter, defaults) { return mailer; }; -module.exports.createTestAccount = function(apiUrl, callback) { +module.exports.createTestAccount = function (apiUrl, callback) { let promise; if (!callback && typeof apiUrl === 'function') { @@ -128,7 +123,7 @@ module.exports.createTestAccount = function(apiUrl, callback) { return promise; }; -module.exports.getTestMessageUrl = function(info) { +module.exports.getTestMessageUrl = function (info) { if (!info || !info.response) { return false; }
lib/sendmail-transport/index.js+8 −0 modified@@ -70,6 +70,14 @@ class SendmailTransport { let returned; let transform; + const hasInvalidAddresses = [] + .concat(envelope.from || []) + .concat(envelope.to || []) + .some(addr => /^-/.test(addr)); + if (hasInvalidAddresses) { + return done(new Error('Can not send mail. Invalid envelope addresses.')); + } + if (this.args) { // force -i to keep single dots args = ['-i'].concat(this.args).concat(envelope.to);
lib/shared/index.js+3 −11 modified@@ -276,7 +276,7 @@ module.exports.getLogger = (options, defaults) => { * @param {Function} reject Function to run if callback ends with an error */ module.exports.callbackPromise = (resolve, reject) => - function() { + function () { let args = Array.from(arguments); let err = args.shift(); if (err) { @@ -357,7 +357,7 @@ module.exports.resolveContent = (data, key, callback) => { /** * Copies properties from source objects to target objects */ -module.exports.assign = function(/* target, ... sources */) { +module.exports.assign = function (/* target, ... sources */) { let args = Array.from(arguments); let target = args.shift() || {}; @@ -489,15 +489,7 @@ function createDefaultLogger(levels) { message = util.format(message, ...args); message.split(/\r?\n/).forEach(line => { - console.log( - '[%s] %s %s', - new Date() - .toISOString() - .substr(0, 19) - .replace(/T/, ' '), - levelNames.get(level), - prefix + line - ); + console.log('[%s] %s %s', new Date().toISOString().substr(0, 19).replace(/T/, ' '), levelNames.get(level), prefix + line); }); };
lib/smtp-connection/http-proxy-client.js+1 −1 modified@@ -44,7 +44,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) { // Error harness for initial connection. Once connection is established, the responsibility // to handle errors is passed to whoever uses this socket let finished = false; - let tempSocketErr = function(err) { + let tempSocketErr = function (err) { if (finished) { return; }
lib/smtp-connection/index.js+4 −14 modified@@ -45,10 +45,7 @@ class SMTPConnection extends EventEmitter { constructor(options) { super(options); - this.id = crypto - .randomBytes(8) - .toString('base64') - .replace(/\W/g, ''); + this.id = crypto.randomBytes(8).toString('base64').replace(/\W/g, ''); this.stage = 'init'; this.options = options || {}; @@ -73,10 +70,7 @@ class SMTPConnection extends EventEmitter { this.customAuth = new Map(); Object.keys(this.options.customAuth || {}).forEach(key => { - let mapKey = (key || '') - .toString() - .trim() - .toUpperCase(); + let mapKey = (key || '').toString().trim().toUpperCase(); if (!mapKey) { return; } @@ -424,11 +418,7 @@ class SMTPConnection extends EventEmitter { this._auth = authData || {}; // Select SASL authentication method - this._authMethod = - (this._auth.method || '') - .toString() - .trim() - .toUpperCase() || false; + this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false; if (!this._authMethod && this._auth.oauth2 && !this._auth.credentials) { this._authMethod = 'XOAUTH2'; @@ -598,7 +588,7 @@ class SMTPConnection extends EventEmitter { // ensure that callback is only called once let returned = false; - let callback = function() { + let callback = function () { if (returned) { return; }
lib/well-known/index.js+1 −1 modified@@ -41,7 +41,7 @@ function normalizeService(service) { * @param {String} key [description] * @returns {Object} SMTP config or false if not found */ -module.exports = function(key) { +module.exports = function (key) { key = normalizeKey(key.split('@').pop()); return normalized[key] || false; };
lib/well-known/services.json+2 −2 modified@@ -22,10 +22,10 @@ "host": "smtp.dynect.net", "port": 25 }, - + "Ethereal": { "aliases": ["ethereal.email"], - "host": "smtp.ethereal.email", + "host": "smtp.ethereal.email", "port": 587 },
lib/xoauth2/index.js+4 −4 modified@@ -263,11 +263,11 @@ class XOAuth2 extends Stream { if (data.error) { // Error Response : https://tools.ietf.org/html/rfc6749#section-5.2 let errorMessage = data.error; - if(data.error_description) { - errorMessage += ': ' + data.error_description; + if (data.error_description) { + errorMessage += ': ' + data.error_description; } - if(data.error_uri) { - errorMessage += ' (' + data.error_uri + ')'; + if (data.error_uri) { + errorMessage += ' (' + data.error_uri + ')'; } return callback(new Error(errorMessage)); }
package.json+1 −1 modified@@ -1,6 +1,6 @@ { "name": "nodemailer", - "version": "6.4.15", + "version": "6.4.16", "description": "Easy as cake e-mail sending from your Node.js applications", "main": "lib/nodemailer.js", "scripts": {
test/base64/base64-test.js+18 −18 modified@@ -12,7 +12,7 @@ const fs = require('fs'); chai.config.includeStack = true; -describe('Base64 Tests', function() { +describe('Base64 Tests', function () { let encodeFixtures = [ ['abcd= ÕÄÖÜ', 'YWJjZD0gw5XDhMOWw5w='], ['foo bar ', 'Zm9vIGJhciAg'], @@ -27,28 +27,28 @@ describe('Base64 Tests', function() { 'MTIzNDU2N\r\nzg5MDEyMz\r\nQ1Njc4ICA\r\n5MA0Kw7XD\r\npMO2w7zDt\r\ncOkw7bDvM\r\nO1w6TDtsO\r\n8w7XDpMO2\r\nw7zDtcOkw\r\n7bDvMO1w6\r\nTDtsO8w7X\r\nDpMO2w7zD\r\ntcOkw7bDv\r\nCBhbm90aG\r\nVyIGxpbmU\r\ngPT09IA==' ]; - describe('#encode', function() { - it('shoud encode UTF-8 string to base64', function() { - encodeFixtures.forEach(function(test) { + describe('#encode', function () { + it('shoud encode UTF-8 string to base64', function () { + encodeFixtures.forEach(function (test) { expect(base64.encode(test[0])).to.equal(test[1]); }); }); - it('shoud encode Buffer to base64', function() { + it('shoud encode Buffer to base64', function () { expect(base64.encode(Buffer.from([0x00, 0x01, 0x02, 0x20, 0x03]))).to.equal('AAECIAM='); }); }); - describe('#wrap', function() { - it('should wrap long base64 encoded lines', function() { - wrapFixtures.forEach(function(test) { + describe('#wrap', function () { + it('should wrap long base64 encoded lines', function () { + wrapFixtures.forEach(function (test) { expect(base64.wrap(test[0], 20)).to.equal(test[1]); }); }); }); - describe('base64 Streams', function() { - it('should transform incoming bytes to base64', function(done) { + describe('base64 Streams', function () { + it('should transform incoming bytes to base64', function (done) { let encoder = new base64.Encoder({ lineLength: 9 }); @@ -58,12 +58,12 @@ describe('Base64 Tests', function() { buf = [], buflen = 0; - encoder.on('data', function(chunk) { + encoder.on('data', function (chunk) { buf.push(chunk); buflen += chunk.length; }); - encoder.on('end', function(chunk) { + encoder.on('end', function (chunk) { if (chunk) { buf.push(chunk); buflen += chunk.length; @@ -74,7 +74,7 @@ describe('Base64 Tests', function() { done(); }); - let sendNextByte = function() { + let sendNextByte = function () { if (i >= bytes.length) { return encoder.end(); } @@ -87,7 +87,7 @@ describe('Base64 Tests', function() { sendNextByte(); }); - it('should transform incoming bytes to base64 and back', function(done) { + it('should transform incoming bytes to base64 and back', function (done) { let decoder = new libbase64.Decoder(); let encoder = new base64.Encoder(); let file = fs.createReadStream(__dirname + '/fixtures/alice.txt'); @@ -97,19 +97,19 @@ describe('Base64 Tests', function() { file.pipe(encoder).pipe(decoder); - file.on('data', function(chunk) { + file.on('data', function (chunk) { fhash.update(chunk); }); - file.on('end', function() { + file.on('end', function () { fhash = fhash.digest('hex'); }); - decoder.on('data', function(chunk) { + decoder.on('data', function (chunk) { dhash.update(chunk); }); - decoder.on('end', function() { + decoder.on('end', function () { dhash = dhash.digest('hex'); expect(fhash).to.equal(dhash); done();
test/dkim/dkim-test.js+7 −7 modified@@ -34,10 +34,10 @@ RpgHY4V0qSCdUt4rD32nwfjlGbh8p5ua5wIDAQAB -----END PUBLIC KEY-----`; */ -describe('DKIM Tests', function() { +describe('DKIM Tests', function () { this.timeout(100 * 1000); // eslint-disable-line - it('should sign message', function(done) { + it('should sign message', function (done) { let message = `From: saatja aadress To: Saaja aadress Subject: pealkiri @@ -110,7 +110,7 @@ teine rida writeNext(); }); - it('should sign large message using cache dir', function(done) { + it('should sign large message using cache dir', function (done) { let dkim = new DKIM({ domainName: 'node.ee', keySelector: 'dkim', @@ -158,7 +158,7 @@ teine rida }); }); - it('should sign large message without cache dir', function(done) { + it('should sign large message without cache dir', function (done) { let dkim = new DKIM({ domainName: 'node.ee', keySelector: 'dkim', @@ -205,7 +205,7 @@ teine rida }); }); - it('should emit cache error', function(done) { + it('should emit cache error', function (done) { let dkim = new DKIM({ domainName: 'node.ee', keySelector: 'dkim', @@ -220,7 +220,7 @@ teine rida }); }); - it('should sign large message as Buffer', function(done) { + it('should sign large message as Buffer', function (done) { let dkim = new DKIM({ domainName: 'node.ee', keySelector: 'dkim', @@ -268,7 +268,7 @@ teine rida }); }); - it('should sign large message as String', function(done) { + it('should sign large message as String', function (done) { let dkim = new DKIM({ domainName: 'node.ee', keySelector: 'dkim',
test/dkim/message-parser-test.js+2 −2 modified@@ -11,8 +11,8 @@ const MessageParser = require('../../lib/dkim/message-parser'); chai.config.includeStack = true; -describe('DKIM MessageParser Tests', function() { - it('should extract header and body', function(done) { +describe('DKIM MessageParser Tests', function () { + it('should extract header and body', function (done) { let parser = new MessageParser(); let message = `From: saatja aadress To: Saaja aadress
test/dkim/relaxed-body-test.js+3 −3 modified@@ -11,8 +11,8 @@ let RelaxedBody = require('../../lib/dkim/relaxed-body'); chai.config.includeStack = true; -describe('DKIM RelaxedBody Tests', function() { - it('Should calculate body hash byte by byte', function(done) { +describe('DKIM RelaxedBody Tests', function () { + it('Should calculate body hash byte by byte', function (done) { fs.readFile(__dirname + '/fixtures/message1.eml', 'utf-8', (err, message) => { expect(err).to.not.exist; @@ -46,7 +46,7 @@ describe('DKIM RelaxedBody Tests', function() { }); }); - it('Should calculate body hash all at once', function(done) { + it('Should calculate body hash all at once', function (done) { fs.readFile(__dirname + '/fixtures/message1.eml', 'utf-8', (err, message) => { expect(err).to.not.exist;
test/dkim/sign-test.js+5 −5 modified@@ -31,8 +31,8 @@ RpgHY4V0qSCdUt4rD32nwfjlGbh8p5ua5wIDAQAB -----END PUBLIC KEY-----`; */ -describe('DKIM Sign Tests', function() { - it('should create relaxed headers', function() { +describe('DKIM Sign Tests', function () { + it('should create relaxed headers', function () { let headerLines = [ { key: 'a', @@ -49,7 +49,7 @@ describe('DKIM Sign Tests', function() { }); }); - it('should skip specific headers', function() { + it('should skip specific headers', function () { let headerLines = [ { key: 'a', @@ -74,7 +74,7 @@ describe('DKIM Sign Tests', function() { }); }); - it('should sign headers', function() { + it('should sign headers', function () { let headerLines = [ { key: 'from', @@ -101,7 +101,7 @@ describe('DKIM Sign Tests', function() { ); }); - it('should sign headers for unicode domain', function() { + it('should sign headers for unicode domain', function () { let headerLines = [ { key: 'from',
test/ethereal-test.js+4 −4 modified@@ -8,9 +8,9 @@ const chai = require('chai'); const expect = chai.expect; chai.config.includeStack = true; -describe('Ethereal Tests', function() { +describe('Ethereal Tests', function () { this.timeout(50 * 1000); // eslint-disable-line no-invalid-this - it('should create an account and send a message', function(done) { + it('should create an account and send a message', function (done) { // Generate SMTP service account from ethereal.email nodemailer.createTestAccount((err, account) => { expect(err).to.not.exist; @@ -43,7 +43,7 @@ describe('Ethereal Tests', function() { }); }); - it('should cache a created test account', function(done) { + it('should cache a created test account', function (done) { nodemailer.createTestAccount((err, account) => { expect(err).to.not.exist; nodemailer.createTestAccount((err, account2) => { @@ -54,7 +54,7 @@ describe('Ethereal Tests', function() { }); }); - it('should cache a created test account when using promises', function(done) { + it('should cache a created test account when using promises', function (done) { nodemailer.createTestAccount().then(account => { nodemailer.createTestAccount().then(account2 => { expect(account2).to.equal(account);
test/fetch/cookies-test.js+28 −28 modified@@ -11,27 +11,27 @@ const Cookies = require('../../lib/fetch/cookies'); chai.config.includeStack = true; -describe('Cookie Tests', function() { +describe('Cookie Tests', function () { let biskviit; - beforeEach(function() { + beforeEach(function () { biskviit = new Cookies(); }); - describe('#getPath', function() { - it('should return root path', function() { + describe('#getPath', function () { + it('should return root path', function () { expect(biskviit.getPath('/')).to.equal('/'); expect(biskviit.getPath('')).to.equal('/'); expect(biskviit.getPath('/index.php')).to.equal('/'); }); - it('should return without file', function() { + it('should return without file', function () { expect(biskviit.getPath('/path/to/file')).to.equal('/path/to/'); }); }); - describe('#isExpired', function() { - it('should match expired cookie', function() { + describe('#isExpired', function () { + it('should match expired cookie', function () { expect( biskviit.isExpired({ name: 'a', @@ -58,8 +58,8 @@ describe('Cookie Tests', function() { }); }); - describe('#compare', function() { - it('should match similar cookies', function() { + describe('#compare', function () { + it('should match similar cookies', function () { expect( biskviit.compare( { @@ -157,8 +157,8 @@ describe('Cookie Tests', function() { }); }); - describe('#add', function() { - it('should append new cookie', function() { + describe('#add', function () { + it('should append new cookie', function () { expect(biskviit.cookies.length).to.equal(0); biskviit.add({ name: 'zzz', @@ -174,7 +174,7 @@ describe('Cookie Tests', function() { expect(biskviit.cookies[0].value).to.equal('abc'); }); - it('should update existing cookie', function() { + it('should update existing cookie', function () { expect(biskviit.cookies.length).to.equal(0); biskviit.add({ name: 'zzz', @@ -200,8 +200,8 @@ describe('Cookie Tests', function() { }); }); - describe('#match', function() { - it('should check if a cookie matches particular domain and path', function() { + describe('#match', function () { + it('should check if a cookie matches particular domain and path', function () { let cookie = { name: 'zzz', value: 'abc', @@ -215,7 +215,7 @@ describe('Cookie Tests', function() { expect(biskviit.match(cookie, 'http://example.com/bef/')).to.be.false; }); - it('should check if a cookie matches particular domain and path', function() { + it('should check if a cookie matches particular domain and path', function () { let cookie = { name: 'zzz', value: 'abc', @@ -229,7 +229,7 @@ describe('Cookie Tests', function() { expect(biskviit.match(cookie, 'http://example.com/bef/')).to.be.false; }); - it('should check if a cookie is secure', function() { + it('should check if a cookie is secure', function () { let cookie = { name: 'zzz', value: 'abc', @@ -244,8 +244,8 @@ describe('Cookie Tests', function() { }); }); - describe('#parse', function() { - it('should parse Set-Cookie value', function() { + describe('#parse', function () { + it('should parse Set-Cookie value', function () { expect(biskviit.parse('theme=plain')).to.deep.equal({ name: 'theme', value: 'plain' @@ -262,7 +262,7 @@ describe('Cookie Tests', function() { }); }); - it('should ignore invalid expire header', function() { + it('should ignore invalid expire header', function () { expect(biskviit.parse('theme=plain; Expires=Wed, 13 Jan 2021 22:23:01 GMT')).to.deep.equal({ name: 'theme', value: 'plain', @@ -276,8 +276,8 @@ describe('Cookie Tests', function() { }); }); - describe('Listing', function() { - beforeEach(function() { + describe('Listing', function () { + beforeEach(function () { biskviit.cookies = [ { name: 'ssid1', @@ -327,8 +327,8 @@ describe('Cookie Tests', function() { ]; }); - describe('#list', function() { - it('should return matching cookies for an URL', function() { + describe('#list', function () { + it('should return matching cookies for an URL', function () { expect(biskviit.list('https://www.foo.com')).to.deep.equal([ { name: 'ssid1', @@ -352,15 +352,15 @@ describe('Cookie Tests', function() { }); }); - describe('#get', function() { - it('should return matching cookies for an URL', function() { + describe('#get', function () { + it('should return matching cookies for an URL', function () { expect(biskviit.get('https://www.foo.com')).to.equal('ssid1=Ap4P….GTEq1; ssid4=Ap4P….GTEq4'); }); }); }); - describe('#set', function() { - it('should set cookie', function() { + describe('#set', function () { + it('should set cookie', function () { // short biskviit.set('theme=plain', 'https://foo.com/'); // long @@ -378,7 +378,7 @@ describe('Cookie Tests', function() { biskviit.set('expired_1=date; Expires=1999-01-01 01:01:01 GMT', 'https://foo.com/'); expect( - biskviit.cookies.map(function(cookie) { + biskviit.cookies.map(function (cookie) { delete cookie.expires; return cookie; })
test/fetch/fetch-test.js+80 −80 modified@@ -67,11 +67,11 @@ const httpsOptions = { '-----END CERTIFICATE-----' }; -describe('Fetch Tests', function() { +describe('Fetch Tests', function () { let httpServer, httpsServer; - beforeEach(function(done) { - httpServer = http.createServer(function(req, res) { + beforeEach(function (done) { + httpServer = http.createServer(function (req, res) { switch (req.url) { case '/redirect6': res.writeHead(302, { @@ -164,13 +164,13 @@ describe('Fetch Tests', function() { case '/post': { let body = []; - req.on('readable', function() { + req.on('readable', function () { let chunk; while ((chunk = req.read()) !== null) { body.push(chunk); } }); - req.on('end', function() { + req.on('end', function () { res.writeHead(200, { 'Content-Type': 'text/plain' }); @@ -187,258 +187,258 @@ describe('Fetch Tests', function() { } }); - httpsServer = https.createServer(httpsOptions, function(req, res) { + httpsServer = https.createServer(httpsOptions, function (req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('Hello World HTTPS\n'); }); - httpServer.listen(HTTP_PORT, function() { + httpServer.listen(HTTP_PORT, function () { httpsServer.listen(HTTPS_PORT, done); }); }); - afterEach(function(done) { - httpServer.close(function() { + afterEach(function (done) { + httpServer.close(function () { httpsServer.close(done); }); }); - it('should fetch HTTP data', function(done) { + it('should fetch HTTP data', function (done) { let req = fetch('http://localhost:' + HTTP_PORT); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('Hello World HTTP\n'); done(); }); }); - it('should fetch HTTPS data', function(done) { + it('should fetch HTTPS data', function (done) { let req = fetch('https://localhost:' + HTTPS_PORT); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('Hello World HTTPS\n'); done(); }); }); - it('should fetch HTTP data with redirects', function(done) { + it('should fetch HTTP data with redirects', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/redirect3'); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('Hello World HTTP\n'); done(); }); }); - it('should return error for too many redirects', function(done) { + it('should return error for too many redirects', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/redirect6'); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); - it('should fetch HTTP data with custom redirect limit', function(done) { + it('should fetch HTTP data with custom redirect limit', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/redirect3', { maxRedirects: 3 }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('Hello World HTTP\n'); done(); }); }); - it('should return error for custom redirect limit', function(done) { + it('should return error for custom redirect limit', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/redirect3', { maxRedirects: 2 }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); - it('should return disable redirects', function(done) { + it('should return disable redirects', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/redirect1', { maxRedirects: 0 }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); - it('should unzip compressed HTTP data', function(done) { + it('should unzip compressed HTTP data', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/gzip'); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('Hello World HTTP\n'); done(); }); }); - it('should return error for unresolved host', function(done) { + it('should return error for unresolved host', function (done) { let req = fetch('http://asfhaskhhgbjdsfhgbsdjgk'); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); - it('should return error for invalid status', function(done) { + it('should return error for invalid status', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/invalid'); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); - it('should allow invalid status', function(done) { + it('should allow invalid status', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/invalid', { allowErrorResponse: true }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.not.exist; }); - req.on('end', function() { + req.on('end', function () { expect(req.statusCode).to.equal(500); expect(Buffer.concat(buf).toString()).to.equal('Hello World HTTP\n'); done(); }); }); - it('should return error for invalid url', function(done) { + it('should return error for invalid url', function (done) { let req = fetch('http://localhost:99999999/'); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); - it('should return timeout error', function(done) { + it('should return timeout error', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/forever', { timeout: 1000 }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); - it('should handle basic HTTP auth', function(done) { + it('should handle basic HTTP auth', function (done) { let req = fetch('http://user:pass@localhost:' + HTTP_PORT + '/auth'); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('user:pass'); done(); }); }); if (!/^0\.10\./.test(process.versions.node)) { // disabled for node 0.10 - it('should return error for invalid protocol', function(done) { + it('should return error for invalid protocol', function (done) { let req = fetch('http://localhost:' + HTTPS_PORT); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); } - it('should set cookie value', function(done) { + it('should set cookie value', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/cookie', { cookie: 'test=pest' }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('test=pest'); done(); }); }); - it('should set user agent', function(done) { + it('should set user agent', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/ua', { userAgent: 'nodemailer-fetch' }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('nodemailer-fetch'); done(); }); }); - it('should post data', function(done) { + it('should post data', function (done) { let req = fetch('http://localhost:' + HTTP_PORT + '/post', { method: 'post', body: { @@ -447,16 +447,16 @@ describe('Fetch Tests', function() { } }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal('hello=world%20%F0%9F%98%AD&another=value'); done(); }); }); - it('should post stream data', function(done) { + it('should post stream data', function (done) { let body = new PassThrough(); let data = Buffer.from('hello=world%20%F0%9F%98%AD&another=value'); @@ -465,16 +465,16 @@ describe('Fetch Tests', function() { body }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('end', function() { + req.on('end', function () { expect(Buffer.concat(buf).toString()).to.equal(data.toString()); done(); }); let pos = 0; - let writeNext = function() { + let writeNext = function () { if (pos >= data.length) { return body.end(); } @@ -486,20 +486,20 @@ describe('Fetch Tests', function() { setImmediate(writeNext); }); - it('should return error for invalid cert', function(done) { + it('should return error for invalid cert', function (done) { let req = fetch('https://localhost:' + HTTPS_PORT, { tls: { rejectUnauthorized: true } }); let buf = []; - req.on('data', function(chunk) { + req.on('data', function (chunk) { buf.push(chunk); }); - req.on('error', function(err) { + req.on('error', function (err) { expect(err).to.exist; done(); }); - req.on('end', function() {}); + req.on('end', function () {}); }); });
test/json-transport/json-transport-test.js+3 −3 modified@@ -10,8 +10,8 @@ const chai = require('chai'); const expect = chai.expect; chai.config.includeStack = true; -describe('JSON Transport Tests', function() { - it('should return an JSON string', function(done) { +describe('JSON Transport Tests', function () { + it('should return an JSON string', function (done) { let transport = nodemailer.createTransport({ jsonTransport: true }); @@ -88,7 +88,7 @@ describe('JSON Transport Tests', function() { }); }); - it('should return an JSON string for calendar event', function(done) { + it('should return an JSON string for calendar event', function (done) { let transport = nodemailer.createTransport({ jsonTransport: true });
test/qp/qp-test.js+19 −19 modified@@ -12,7 +12,7 @@ const fs = require('fs'); chai.config.includeStack = true; -describe('Quoted-Printable Tests', function() { +describe('Quoted-Printable Tests', function () { let encodeFixtures = [ ['abcd= ÕÄÖÜ', 'abcd=3D =C3=95=C3=84=C3=96=C3=9C'], ['foo bar ', 'foo bar =20'], @@ -32,32 +32,32 @@ describe('Quoted-Printable Tests', function() { '12345678=\r\n90123456=\r\n78=20=20=\r\n90\r\n=C3=B5=\r\n=C3=A4=\r\n=C3=B6=\r\n=C3=BC=\r\n=C3=B5=\r\n=C3=A4=\r\n=C3=B6=\r\n=C3=BC=\r\n=C3=B5=\r\n=C3=A4=\r\n=C3=B6=\r\n=C3=BC=\r\n=C3=B5=\r\n=C3=A4=\r\n=C3=B6=\r\n=C3=BC=\r\n=C3=B5=\r\n=C3=A4=\r\n=C3=B6=\r\n=C3=BC=\r\n=C3=B5=\r\n=C3=A4=\r\n=C3=B6=\r\n=C3=BC=\r\n=C3=B5=\r\n=C3=A4=\r\n=C3=B6=\r\n=C3=BC=\r\n=C3=B5=\r\n=C3=A4=\r\n=C3=B6=\r\n=C3=BC=\r\n=20anoth=\r\ner=20lin=\r\ne=20=3D=\r\n=3D=3D=20' ]; - describe('#encode', function() { - it('shoud encode UTF-8 string to QP', function() { - encodeFixtures.forEach(function(test) { + describe('#encode', function () { + it('shoud encode UTF-8 string to QP', function () { + encodeFixtures.forEach(function (test) { expect(qp.encode(test[0])).to.equal(test[1]); }); }); - it('shoud encode Buffer to QP', function() { + it('shoud encode Buffer to QP', function () { expect(qp.encode(Buffer.from([0x00, 0x01, 0x02, 0x20, 0x03]))).to.equal('=00=01=02 =03'); }); }); - describe('#wrap', function() { - it('should wrap long QP encoded lines', function() { - wrapFixtures.forEach(function(test) { + describe('#wrap', function () { + it('should wrap long QP encoded lines', function () { + wrapFixtures.forEach(function (test) { expect(qp.wrap(test[0], 20)).to.equal(test[1]); }); }); - it('should wrap line ending with <CR>', function() { + it('should wrap line ending with <CR>', function () { expect(qp.wrap('alfa palfa kalfa ralfa\r', 10)).to.equal('alfa palf=\r\na kalfa =\r\nralfa\r'); }); }); - describe('QP Streams', function() { - it('should transform incoming bytes to QP', function(done) { + describe('QP Streams', function () { + it('should transform incoming bytes to QP', function (done) { let encoder = new qp.Encoder({ lineLength: 9 }); @@ -67,12 +67,12 @@ describe('Quoted-Printable Tests', function() { buf = [], buflen = 0; - encoder.on('data', function(chunk) { + encoder.on('data', function (chunk) { buf.push(chunk); buflen += chunk.length; }); - encoder.on('end', function(chunk) { + encoder.on('end', function (chunk) { if (chunk) { buf.push(chunk); buflen += chunk.length; @@ -83,7 +83,7 @@ describe('Quoted-Printable Tests', function() { done(); }); - let sendNextByte = function() { + let sendNextByte = function () { if (i >= bytes.length) { return encoder.end(); } @@ -96,7 +96,7 @@ describe('Quoted-Printable Tests', function() { sendNextByte(); }); - it('should transform incoming bytes to QP and back', function(done) { + it('should transform incoming bytes to QP and back', function (done) { let decoder = new libqp.Decoder(); let encoder = new qp.Encoder(); let file = fs.createReadStream(__dirname + '/fixtures/alice.txt'); @@ -106,19 +106,19 @@ describe('Quoted-Printable Tests', function() { file.pipe(encoder).pipe(decoder); - file.on('data', function(chunk) { + file.on('data', function (chunk) { fhash.update(chunk); }); - file.on('end', function() { + file.on('end', function () { fhash = fhash.digest('hex'); }); - decoder.on('data', function(chunk) { + decoder.on('data', function (chunk) { dhash.update(chunk); }); - decoder.on('end', function() { + decoder.on('end', function () { dhash = dhash.digest('hex'); expect(fhash).to.equal(dhash); done();
test/sendmail/le-unix.test.js+3 −3 modified@@ -9,8 +9,8 @@ const expect = chai.expect; chai.config.includeStack = true; -describe('Sendmail Unix Newlines', function() { - it('should rewrite all linebreaks (byte by byte)', function(done) { +describe('Sendmail Unix Newlines', function () { + it('should rewrite all linebreaks (byte by byte)', function (done) { let source = 'tere tere\nteine rida\nkolmas rida\r\nneljas rida\r\nviies rida\n kuues rida'; let chunks = []; @@ -34,7 +34,7 @@ describe('Sendmail Unix Newlines', function() { setImmediate(writeNextByte); }); - it('should rewrite all linebreaks (all at once)', function(done) { + it('should rewrite all linebreaks (all at once)', function (done) { let source = 'tere tere\nteine rida\nkolmas rida\r\nneljas rida\r\nviies rida\n kuues rida'; let chunks = [];
test/sendmail/le-windows-test.js+3 −3 modified@@ -9,8 +9,8 @@ const expect = chai.expect; chai.config.includeStack = true; -describe('Sendmail Windows Newlines', function() { - it('should rewrite all linebreaks (byte by byte)', function(done) { +describe('Sendmail Windows Newlines', function () { + it('should rewrite all linebreaks (byte by byte)', function (done) { let source = 'tere tere\nteine rida\nkolmas rida\r\nneljas rida\r\nviies rida\n kuues rida'; let chunks = []; @@ -34,7 +34,7 @@ describe('Sendmail Windows Newlines', function() { setImmediate(writeNextByte); }); - it('should rewrite all linebreaks (all at once)', function(done) { + it('should rewrite all linebreaks (all at once)', function (done) { let source = 'tere tere\nteine rida\nkolmas rida\r\nneljas rida\r\nviies rida\n kuues rida'; let chunks = [];
test/sendmail/sendmail-test.js+49 −9 modified@@ -39,26 +39,26 @@ class MockBuilder { } } -describe('Sendmail Transport Tests', function() { - it('Should expose version number', function() { +describe('Sendmail Transport Tests', function () { + it('Should expose version number', function () { let client = new SendmailTransport(); expect(client.name).to.exist; expect(client.version).to.exist; }); - it('Should send message', function(done) { + it('Should send message', function (done) { let client = new SendmailTransport(); let stubbedSpawn = new EventEmitter(); stubbedSpawn.stdin = new PassThrough(); stubbedSpawn.stdout = new PassThrough(); let output = ''; - stubbedSpawn.stdin.on('data', function(chunk) { + stubbedSpawn.stdin.on('data', function (chunk) { output += chunk.toString(); }); - stubbedSpawn.stdin.on('end', function() { + stubbedSpawn.stdin.on('end', function () { stubbedSpawn.emit('close', 0); stubbedSpawn.emit('exit', 0); }); @@ -76,7 +76,7 @@ describe('Sendmail Transport Tests', function() { 'message\r\nline 2' ) }, - function(err, data) { + function (err, data) { expect(err).to.not.exist; expect(data.messageId).to.equal('<test>'); expect(output).to.equal('message\nline 2'); @@ -86,7 +86,47 @@ describe('Sendmail Transport Tests', function() { ); }); - it('Should return an error', function(done) { + it('Should reject message', function (done) { + let client = new SendmailTransport(); + + let stubbedSpawn = new EventEmitter(); + stubbedSpawn.stdin = new PassThrough(); + stubbedSpawn.stdout = new PassThrough(); + + let output = ''; + stubbedSpawn.stdin.on('data', function (chunk) { + output += chunk.toString(); + }); + + stubbedSpawn.stdin.on('end', function () { + stubbedSpawn.emit('close', 0); + stubbedSpawn.emit('exit', 0); + }); + + sinon.stub(client, '_spawn').returns(stubbedSpawn); + + client.send( + { + data: {}, + message: new MockBuilder( + { + from: 'test@valid.sender', + to: '-d0.1a@example.com' + }, + 'message\r\nline 2' + ) + }, + function (err, data) { + expect(err).to.exist; + expect(data).to.not.exist; + expect(output).to.equal(''); + client._spawn.restore(); + done(); + } + ); + }); + + it('Should return an error', function (done) { let client = new SendmailTransport(); let stubbedSpawn = new EventEmitter(); @@ -95,7 +135,7 @@ describe('Sendmail Transport Tests', function() { stubbedSpawn.stdin.on('data', () => false); - stubbedSpawn.stdin.on('end', function() { + stubbedSpawn.stdin.on('end', function () { stubbedSpawn.emit('close', 127); stubbedSpawn.emit('exit', 127); }); @@ -113,7 +153,7 @@ describe('Sendmail Transport Tests', function() { 'message\r\nline 2' ) }, - function(err, data) { + function (err, data) { expect(err).to.exist; expect(data).to.not.exist; client._spawn.restore();
test/ses-transport/ses-transport-test.js+8 −8 modified@@ -21,10 +21,10 @@ cmDrj/7jJHb+ykFNb7GaEkiSYqzUjKkfpweBDYECMFJUyzuuFJAjq3BXmGJlyykQ TweUw+zMVdSXjO+FCPcYNi6CP1t1KoESzGKBVoqA/g== -----END RSA PRIVATE KEY-----`; -describe('SES Transport Tests', function() { +describe('SES Transport Tests', function () { this.timeout(50 * 1000); // eslint-disable-line no-invalid-this - it('should return MessageId', function(done) { + it('should return MessageId', function (done) { let transport = nodemailer.createTransport({ SES: { config: { @@ -73,7 +73,7 @@ describe('SES Transport Tests', function() { }); }); - it('should sign message with DKIM', function(done) { + it('should sign message with DKIM', function (done) { let transport = nodemailer.createTransport({ SES: { config: { @@ -127,7 +127,7 @@ describe('SES Transport Tests', function() { }); }); - it('should limit parallel connections', function(done) { + it('should limit parallel connections', function (done) { let transport = nodemailer.createTransport({ maxConnections: 2, SES: { @@ -188,7 +188,7 @@ describe('SES Transport Tests', function() { } }); - it('should rate limit messages', function(done) { + it('should rate limit messages', function (done) { let transport = nodemailer.createTransport({ sendingRate: 10, SES: { @@ -249,7 +249,7 @@ describe('SES Transport Tests', function() { } }); - it('should rate limit long messages', function(done) { + it('should rate limit long messages', function (done) { let transport = nodemailer.createTransport({ sendingRate: 30, SES: { @@ -310,7 +310,7 @@ describe('SES Transport Tests', function() { } }); - it('should rate limit messages and connections', function(done) { + it('should rate limit messages and connections', function (done) { let transport = nodemailer.createTransport({ sendingRate: 100, maxConnections: 1, @@ -373,7 +373,7 @@ describe('SES Transport Tests', function() { } }); - it('detect sending slots on idle events', function(done) { + it('detect sending slots on idle events', function (done) { let transport = nodemailer.createTransport({ sendingRate: 100, maxConnections: 1,
test/shared/shared-test.js+45 −45 modified@@ -13,9 +13,9 @@ const zlib = require('zlib'); chai.config.includeStack = true; -describe('Shared Funcs Tests', function() { - describe('Logger tests', function() { - it('Should create a logger', function() { +describe('Shared Funcs Tests', function () { + describe('Logger tests', function () { + it('Should create a logger', function () { expect( typeof shared.getLogger({ logger: false @@ -30,8 +30,8 @@ describe('Shared Funcs Tests', function() { }); }); - describe('Connection url parser tests', function() { - it('Should parse connection url', function() { + describe('Connection url parser tests', function () { + it('Should parse connection url', function () { let url = 'smtps://user:pass@localhost:123?tls.rejectUnauthorized=false&name=horizon'; expect(shared.parseConnectionUrl(url)).to.deep.equal({ secure: true, @@ -48,7 +48,7 @@ describe('Shared Funcs Tests', function() { }); }); - it('should not choke on special symbols in auth', function() { + it('should not choke on special symbols in auth', function () { let url = 'smtps://user%40gmail.com:%3Apasswith%25Char@smtp.gmail.com'; expect(shared.parseConnectionUrl(url)).to.deep.equal({ secure: true, @@ -61,12 +61,12 @@ describe('Shared Funcs Tests', function() { }); }); - describe('Resolver tests', function() { + describe('Resolver tests', function () { let port = 10337; let server; - beforeEach(function(done) { - server = http.createServer(function(req, res) { + beforeEach(function (done) { + server = http.createServer(function (req, res) { if (/redirect/.test(req.url)) { res.writeHead(302, { Location: 'http://localhost:' + port + '/message.html' @@ -92,103 +92,103 @@ describe('Shared Funcs Tests', function() { server.listen(port, done); }); - afterEach(function(done) { + afterEach(function (done) { server.close(done); }); - it('should set text from html string', function(done) { + it('should set text from html string', function (done) { let mail = { data: { html: '<p>Tere, tere</p><p>vana kere!</p>\n' } }; - shared.resolveContent(mail.data, 'html', function(err, value) { + shared.resolveContent(mail.data, 'html', function (err, value) { expect(err).to.not.exist; expect(value).to.equal('<p>Tere, tere</p><p>vana kere!</p>\n'); done(); }); }); - it('should set text from html buffer', function(done) { + it('should set text from html buffer', function (done) { let mail = { data: { html: Buffer.from('<p>Tere, tere</p><p>vana kere!</p>\n') } }; - shared.resolveContent(mail.data, 'html', function(err, value) { + shared.resolveContent(mail.data, 'html', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal(mail.data.html); done(); }); }); - it('should set text from a html file', function(done) { + it('should set text from a html file', function (done) { let mail = { data: { html: { path: __dirname + '/fixtures/message.html' } } }; - shared.resolveContent(mail.data, 'html', function(err, value) { + shared.resolveContent(mail.data, 'html', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal(Buffer.from('<p>Tere, tere</p><p>vana kere!</p>\n')); done(); }); }); - it('should set text from an html url', function(done) { + it('should set text from an html url', function (done) { let mail = { data: { html: { path: 'http://localhost:' + port + '/message.html' } } }; - shared.resolveContent(mail.data, 'html', function(err, value) { + shared.resolveContent(mail.data, 'html', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal(Buffer.from('<p>Tere, tere</p><p>vana kere!</p>\n')); done(); }); }); - it('should set text from redirecting url', function(done) { + it('should set text from redirecting url', function (done) { let mail = { data: { html: { path: 'http://localhost:' + port + '/redirect.html' } } }; - shared.resolveContent(mail.data, 'html', function(err, value) { + shared.resolveContent(mail.data, 'html', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal(Buffer.from('<p>Tere, tere</p><p>vana kere!</p>\n')); done(); }); }); - it('should set text from gzipped url', function(done) { + it('should set text from gzipped url', function (done) { let mail = { data: { html: { path: 'http://localhost:' + port + '/compressed.html' } } }; - shared.resolveContent(mail.data, 'html', function(err, value) { + shared.resolveContent(mail.data, 'html', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal(Buffer.from('<p>Tere, tere</p><p>vana kere!</p>\n')); done(); }); }); - it('should set text from a html stream', function(done) { + it('should set text from a html stream', function (done) { let mail = { data: { html: fs.createReadStream(__dirname + '/fixtures/message.html') } }; - shared.resolveContent(mail.data, 'html', function(err, value) { + shared.resolveContent(mail.data, 'html', function (err, value) { expect(err).to.not.exist; expect(mail).to.deep.equal({ data: { @@ -200,21 +200,21 @@ describe('Shared Funcs Tests', function() { }); }); - it('should return an error', function(done) { + it('should return an error', function (done) { let mail = { data: { html: { path: 'http://localhost:' + (port + 1000) + '/message.html' } } }; - shared.resolveContent(mail.data, 'html', function(err) { + shared.resolveContent(mail.data, 'html', function (err) { expect(err).to.exist; done(); }); }); - it('should return encoded string as buffer', function(done) { + it('should return encoded string as buffer', function (done) { let str = '<p>Tere, tere</p><p>vana kere!</p>\n'; let mail = { data: { @@ -224,15 +224,15 @@ describe('Shared Funcs Tests', function() { } } }; - shared.resolveContent(mail.data, 'html', function(err, value) { + shared.resolveContent(mail.data, 'html', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal(Buffer.from(str)); done(); }); }); - describe('data uri tests', function() { - it('should resolve with mime type and base64', function(done) { + describe('data uri tests', function () { + it('should resolve with mime type and base64', function (done) { let mail = { data: { attachment: { @@ -241,7 +241,7 @@ describe('Shared Funcs Tests', function() { } } }; - shared.resolveContent(mail.data, 'attachment', function(err, value) { + shared.resolveContent(mail.data, 'attachment', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal( Buffer.from( @@ -253,37 +253,37 @@ describe('Shared Funcs Tests', function() { }); }); - it('should resolve with mime type and plaintext', function(done) { + it('should resolve with mime type and plaintext', function (done) { let mail = { data: { attachment: { path: 'data:image/png,tere%20tere' } } }; - shared.resolveContent(mail.data, 'attachment', function(err, value) { + shared.resolveContent(mail.data, 'attachment', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal(Buffer.from('tere tere')); done(); }); }); - it('should resolve with plaintext', function(done) { + it('should resolve with plaintext', function (done) { let mail = { data: { attachment: { path: 'data:,tere%20tere' } } }; - shared.resolveContent(mail.data, 'attachment', function(err, value) { + shared.resolveContent(mail.data, 'attachment', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal(Buffer.from('tere tere')); done(); }); }); - it('should resolve with mime type, charset and base64', function(done) { + it('should resolve with mime type, charset and base64', function (done) { let mail = { data: { attachment: { @@ -292,7 +292,7 @@ describe('Shared Funcs Tests', function() { } } }; - shared.resolveContent(mail.data, 'attachment', function(err, value) { + shared.resolveContent(mail.data, 'attachment', function (err, value) { expect(err).to.not.exist; expect(value).to.deep.equal( Buffer.from( @@ -306,8 +306,8 @@ describe('Shared Funcs Tests', function() { }); }); - describe('#assign tests', function() { - it('should assign multiple objects to target', function() { + describe('#assign tests', function () { + it('should assign multiple objects to target', function () { let target = { a: 1, b: 2, @@ -336,24 +336,24 @@ describe('Shared Funcs Tests', function() { }); }); - describe('#encodeXText tests', function() { - it('should not encode atom', function() { + describe('#encodeXText tests', function () { + it('should not encode atom', function () { expect(shared.encodeXText('teretere')).to.equal('teretere'); }); - it('should not encode email', function() { + it('should not encode email', function () { expect(shared.encodeXText('andris.reinman@gmail.com')).to.equal('andris.reinman@gmail.com'); }); - it('should encode space', function() { + it('should encode space', function () { expect(shared.encodeXText('tere tere')).to.equal('tere+20tere'); }); - it('should encode unicode', function() { + it('should encode unicode', function () { expect(shared.encodeXText('tere tõre')).to.equal('tere+20t+C3+B5re'); }); - it('should encode low codes', function() { + it('should encode low codes', function () { expect(shared.encodeXText('tere t\tre')).to.equal('tere+20t+09re'); }); });
test/smtp-connection/http-proxy-client-test.js+4 −4 modified@@ -15,8 +15,8 @@ chai.config.includeStack = true; const PROXY_PORT = 3128; const TARGET_PORT = 3129; -describe('HTTP Proxy Client Tests', function() { - it('should connect to a socket through proxy', function(done) { +describe('HTTP Proxy Client Tests', function () { + it('should connect to a socket through proxy', function (done) { let smtpServer = new SMTPServer({ logger: false }); @@ -38,7 +38,7 @@ describe('HTTP Proxy Client Tests', function() { }); }); }); - it('should connect to a socket through proxy with auth', function(done) { + it('should connect to a socket through proxy with auth', function (done) { let smtpServer = new SMTPServer({ logger: false }); @@ -64,7 +64,7 @@ describe('HTTP Proxy Client Tests', function() { }); }); - it('should should fail auth', function(done) { + it('should should fail auth', function (done) { let smtpServer = new SMTPServer({ logger: false });
test/smtp-connection/smtp-connection-test.js+177 −192 modified@@ -24,38 +24,38 @@ let PROXY_PORT_NUMBER = 9999; let LMTP_PORT_NUMBER = 8396; let XOAUTH_PORT = 8497; -describe('SMTP-Connection Tests', function() { - describe('Version test', function() { - it('Should expose version number', function() { +describe('SMTP-Connection Tests', function () { + describe('Version test', function () { + it('Should expose version number', function () { let client = new SMTPConnection(); expect(client.version).to.equal(packageData.version); }); }); - describe('Connection tests', function() { + describe('Connection tests', function () { let server, insecureServer, invalidServer, secureServer, httpProxy; - beforeEach(function(done) { + beforeEach(function (done) { server = new SMTPServer({ - onAuth: function(auth, session, callback) { + onAuth: function (auth, session, callback) { if (auth.username !== 'testuser' || auth.password !== 'testpass') { return callback(new Error('Invalid username or password')); } callback(null, { user: 123 }); }, - onData: function(stream, session, callback) { - stream.on('data', function() {}); + onData: function (stream, session, callback) { + stream.on('data', function () {}); stream.on('end', callback); } }); insecureServer = new SMTPServer({ disabledCommands: ['STARTTLS', 'AUTH'], - onData: function(stream, session, callback) { + onData: function (stream, session, callback) { let err = false; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { if (err || session.use8BitMime) { return; } @@ -65,259 +65,259 @@ describe('SMTP-Connection Tests', function() { } } }); - stream.on('end', function() { + stream.on('end', function () { callback(err, false); }); }, logger: false }); - invalidServer = net.createServer(function() {}); + invalidServer = net.createServer(function () {}); secureServer = new SMTPServer({ secure: true, - onAuth: function(auth, session, callback) { + onAuth: function (auth, session, callback) { if (auth.username !== 'testuser' || auth.password !== 'testpass') { return callback(new Error('Invalid username or password')); } callback(null, { user: 123 }); }, - onData: function(stream, session, callback) { - stream.on('data', function() {}); + onData: function (stream, session, callback) { + stream.on('data', function () {}); stream.on('end', callback); }, logger: false }); httpProxy = new HttpConnectProxy(); - server.listen(PORT_NUMBER, function() { - invalidServer.listen(PORT_NUMBER + 1, function() { - secureServer.listen(PORT_NUMBER + 2, function() { - insecureServer.listen(PORT_NUMBER + 3, function() { + server.listen(PORT_NUMBER, function () { + invalidServer.listen(PORT_NUMBER + 1, function () { + secureServer.listen(PORT_NUMBER + 2, function () { + insecureServer.listen(PORT_NUMBER + 3, function () { httpProxy.listen(PROXY_PORT_NUMBER, done); }); }); }); }); }); - afterEach(function(done) { - server.close(function() { - invalidServer.close(function() { - secureServer.close(function() { - insecureServer.close(function() { + afterEach(function (done) { + server.close(function () { + invalidServer.close(function () { + secureServer.close(function () { + insecureServer.close(function () { httpProxy.close(done); }); }); }); }); }); - it('should connect to unsecure server', function(done) { + it('should connect to unsecure server', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER + 3, ignoreTLS: true, logger: false }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.false; client.close(); }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err).to.not.exist; }); client.on('end', done); }); - it('should connect to a server and upgrade with STARTTLS', function(done) { + it('should connect to a server and upgrade with STARTTLS', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER, logger: false }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.true; client.close(); }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err).to.not.exist; }); client.on('end', done); }); - it('should connect to a server and upgrade with forced STARTTLS', function(done) { + it('should connect to a server and upgrade with forced STARTTLS', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER, requireTLS: true, transactionLog: true, logger: false }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.true; client.close(); }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err).to.not.exist; }); client.on('end', done); }); - it('should connect to a server and try to upgrade STARTTLS', function(done) { + it('should connect to a server and try to upgrade STARTTLS', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER + 3, logger: false, requireTLS: true, opportunisticTLS: true }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.false; client.close(); }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err).to.not.exist; }); client.on('end', done); }); - it('should try upgrade with STARTTLS where not advertised', function(done) { + it('should try upgrade with STARTTLS where not advertised', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER + 3, requireTLS: true, logger: false }); - client.connect(function() { + client.connect(function () { // should not run expect(false).to.be.true; client.close(); }); - client.once('error', function(err) { + client.once('error', function (err) { expect(err).to.exist; }); client.on('end', done); }); - it('should close connection after STARTTLS', function(done) { + it('should close connection after STARTTLS', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER, logger: false }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.true; - server.connections.forEach(function(conn) { + server.connections.forEach(function (conn) { conn.close(); }); }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err.message).to.equal('Connection closed unexpectedly'); }); client.on('end', done); }); - it('should connect to a secure server', function(done) { + it('should connect to a secure server', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER + 2, secure: true, logger: false }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.true; client.close(); }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err).to.not.exist; }); client.on('end', done); }); - it('should emit error for invalid port', function(done) { + it('should emit error for invalid port', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER + 10, logger: false }); - client.connect(function() { + client.connect(function () { // should not run expect(false).to.be.true; client.close(); }); - client.once('error', function(err) { + client.once('error', function (err) { expect(err).to.exist; }); client.on('end', done); }); - it('should emit error for too large port', function(done) { + it('should emit error for too large port', function (done) { let client = new SMTPConnection({ port: 999999999, logger: false }); - client.connect(function() { + client.connect(function () { // should not run expect(false).to.be.true; client.close(); }); - client.once('error', function(err) { + client.once('error', function (err) { expect(err).to.exist; }); client.on('end', done); }); - it('should emit inactivity timeout error', function(done) { + it('should emit inactivity timeout error', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER, socketTimeout: 100, logger: false }); - client.connect(function() { + client.connect(function () { // do nothing }); - client.once('error', function(err) { + client.once('error', function (err) { expect(err).to.exist; expect(err.code).to.equal('ETIMEDOUT'); }); client.on('end', done); }); - it('should connect through proxy', function(done) { - let runTest = function(socket) { + it('should connect through proxy', function (done) { + let runTest = function (socket) { let client = new SMTPConnection({ logger: false, port: PORT_NUMBER, connection: socket }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.true; client.login( { @@ -327,37 +327,37 @@ describe('SMTP-Connection Tests', function() { pass: 'testpass' } }, - function(err) { + function (err) { expect(err).to.not.exist; expect(client.authenticated).to.be.true; client.close(); } ); }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err).to.not.exist; }); client.on('end', done); }; - proxyConnect(PROXY_PORT_NUMBER, '127.0.0.1', PORT_NUMBER, '127.0.0.1', function(err, socket) { + proxyConnect(PROXY_PORT_NUMBER, '127.0.0.1', PORT_NUMBER, '127.0.0.1', function (err, socket) { expect(err).to.not.exist; runTest(socket); }); }); - it('should connect through proxy to secure server', function(done) { - let runTest = function(socket) { + it('should connect through proxy to secure server', function (done) { + let runTest = function (socket) { let client = new SMTPConnection({ logger: false, port: PORT_NUMBER + 2, secure: true, connection: socket }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.true; client.login( { @@ -367,58 +367,53 @@ describe('SMTP-Connection Tests', function() { pass: 'testpass' } }, - function(err) { + function (err) { expect(err).to.not.exist; expect(client.authenticated).to.be.true; client.close(); } ); }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err).to.not.exist; }); client.on('end', done); }; - proxyConnect(PROXY_PORT_NUMBER, '127.0.0.1', PORT_NUMBER + 2, '127.0.0.1', function(err, socket) { + proxyConnect(PROXY_PORT_NUMBER, '127.0.0.1', PORT_NUMBER + 2, '127.0.0.1', function (err, socket) { expect(err).to.not.exist; runTest(socket); }); }); - it('should send to unsecure server', function(done) { + it('should send to unsecure server', function (done) { let client = new SMTPConnection({ port: PORT_NUMBER + 3, ignoreTLS: true, logger: false }); - client.on('error', function(err) { + client.on('error', function (err) { expect(err).to.not.exist; }); - client.connect(function() { + client.connect(function () { expect(client.secure).to.be.false; let chunks = [], fname = __dirname + '/../../LICENSE', message = fs.readFileSync(fname, 'utf-8'); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); server.removeAllListeners('dataReady'); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); - expect(body.toString()).to.equal( - message - .toString() - .trim() - .replace(/\n/g, '\r\n') - ); + expect(body.toString()).to.equal(message.toString().trim().replace(/\n/g, '\r\n')); callback(null, 'ABC1'); }); @@ -428,7 +423,7 @@ describe('SMTP-Connection Tests', function() { to: 'test@valid.recipient' }, fs.createReadStream(fname), - function(err) { + function (err) { expect(err).to.not.exist; client.close(); } @@ -439,7 +434,7 @@ describe('SMTP-Connection Tests', function() { }); }); - describe('Login tests', function() { + describe('Login tests', function () { this.timeout(10 * 1000); let server, @@ -448,16 +443,16 @@ describe('SMTP-Connection Tests', function() { lmtpClient, testtoken = 'testtoken'; - beforeEach(function(done) { + beforeEach(function (done) { server = new SMTPServer({ authMethods: ['PLAIN', 'XOAUTH2'], disabledCommands: ['STARTTLS'], size: 100 * 1024, - onData: function(stream, session, callback) { + onData: function (stream, session, callback) { let err = false; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { if (err || session.use8BitMime) { return; } @@ -467,12 +462,12 @@ describe('SMTP-Connection Tests', function() { } } }); - stream.on('end', function() { + stream.on('end', function () { callback(err, false); }); }, - onAuth: function(auth, session, callback) { + onAuth: function (auth, session, callback) { if (auth.method !== 'XOAUTH2') { if (auth.username !== 'testuser' || auth.password !== 'testpass') { return callback(new Error('Invalid username or password')); @@ -490,7 +485,7 @@ describe('SMTP-Connection Tests', function() { user: 123 }); }, - onMailFrom: function(address, session, callback) { + onMailFrom: function (address, session, callback) { if (address.args && parseInt(address.args.SIZE, 10) > 50 * 1024) { return callback(new Error('452 Insufficient channel storage: ' + address.address)); } @@ -513,7 +508,7 @@ describe('SMTP-Connection Tests', function() { return callback(); // Accept the address }, - onRcptTo: function(address, session, callback) { + onRcptTo: function (address, session, callback) { if (!/@valid.recipient/.test(address.address)) { return callback(new Error('Only user@valid.recipient is allowed to receive mail')); } @@ -529,10 +524,10 @@ describe('SMTP-Connection Tests', function() { lmtp: true, disabledCommands: ['STARTTLS', 'AUTH'], - onData: function(stream, session, callback) { - stream.on('data', function() {}); - stream.on('end', function() { - let response = session.envelope.rcptTo.map(function(rcpt, i) { + onData: function (stream, session, callback) { + stream.on('data', function () {}); + stream.on('end', function () { + let response = session.envelope.rcptTo.map(function (rcpt, i) { if (i % 2) { return '<' + rcpt.address + '> Accepted'; } else { @@ -542,13 +537,13 @@ describe('SMTP-Connection Tests', function() { callback(null, response); }); }, - onMailFrom: function(address, session, callback) { + onMailFrom: function (address, session, callback) { if (!/@valid.sender/.test(address.address)) { return callback(new Error('Only user@valid.sender is allowed to send mail')); } return callback(); // Accept the address }, - onRcptTo: function(address, session, callback) { + onRcptTo: function (address, session, callback) { if (!/@valid.recipient/.test(address.address)) { return callback(new Error('Only user@valid.recipient is allowed to receive mail')); } @@ -570,24 +565,24 @@ describe('SMTP-Connection Tests', function() { debug: false }); - server.listen(PORT_NUMBER, function() { - lmtpServer.listen(LMTP_PORT_NUMBER, function() { - client.connect(function() { + server.listen(PORT_NUMBER, function () { + lmtpServer.listen(LMTP_PORT_NUMBER, function () { + client.connect(function () { lmtpClient.connect(done); }); }); }); }); - afterEach(function(done) { + afterEach(function (done) { client.close(); lmtpClient.close(); - server.close(function() { + server.close(function () { lmtpServer.close(done); }); }); - it('should login', function(done) { + it('should login', function (done) { expect(client.authenticated).to.be.false; client.login( { @@ -597,15 +592,15 @@ describe('SMTP-Connection Tests', function() { pass: 'testpass' } }, - function(err) { + function (err) { expect(err).to.not.exist; expect(client.authenticated).to.be.true; done(); } ); }); - it('should return error for invalid login', function(done) { + it('should return error for invalid login', function (done) { expect(client.authenticated).to.be.false; client.login( { @@ -615,7 +610,7 @@ describe('SMTP-Connection Tests', function() { pass: 'invalid' } }, - function(err) { + function (err) { expect(err).to.exist; expect(client.authenticated).to.be.false; expect(err.code).to.equal('EAUTH'); @@ -625,13 +620,13 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should return error for missing credentials', function(done) { + it('should return error for missing credentials', function (done) { expect(client.authenticated).to.be.false; client.login( { user: 'testuser' }, - function(err) { + function (err) { expect(err).to.exist; expect(client.authenticated).to.be.false; expect(err.message).to.match(/^Missing credentials/); @@ -642,7 +637,7 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should return error for incomplete credentials', function(done) { + it('should return error for incomplete credentials', function (done) { expect(client.authenticated).to.be.false; client.login( { @@ -651,7 +646,7 @@ describe('SMTP-Connection Tests', function() { user: 'testuser' } }, - function(err) { + function (err) { expect(err).to.exist; expect(client.authenticated).to.be.false; expect(err.message).to.match(/^Missing credentials/); @@ -662,14 +657,14 @@ describe('SMTP-Connection Tests', function() { ); }); - describe('xoauth2 login', function() { + describe('xoauth2 login', function () { this.timeout(10 * 1000); let x2server; - beforeEach(function(done) { + beforeEach(function (done) { x2server = xoauth2Server({ port: XOAUTH_PORT, - onUpdate: function(username, accessToken) { + onUpdate: function (username, accessToken) { testtoken = accessToken; }.bind(this) }); @@ -679,11 +674,11 @@ describe('SMTP-Connection Tests', function() { x2server.start(done); }); - afterEach(function(done) { + afterEach(function (done) { x2server.stop(done); }); - it('should login with xoauth2 string', function(done) { + it('should login with xoauth2 string', function (done) { expect(client.authenticated).to.be.false; client.login( { @@ -694,15 +689,15 @@ describe('SMTP-Connection Tests', function() { accessToken: testtoken }) }, - function(err) { + function (err) { expect(err).to.not.exist; expect(client.authenticated).to.be.true; done(); } ); }); - it('should return error for invalid xoauth2 string token', function(done) { + it('should return error for invalid xoauth2 string token', function (done) { expect(client.authenticated).to.be.false; client.login( { @@ -713,7 +708,7 @@ describe('SMTP-Connection Tests', function() { accessToken: 'invalid' }) }, - function(err) { + function (err) { expect(err).to.exist; expect(client.authenticated).to.be.false; expect(err.code).to.equal('EAUTH'); @@ -722,7 +717,7 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should login with xoauth2 object', function(done) { + it('should login with xoauth2 object', function (done) { expect(client.authenticated).to.be.false; client.login( { @@ -737,15 +732,15 @@ describe('SMTP-Connection Tests', function() { accessUrl: 'http://localhost:' + XOAUTH_PORT }) }, - function(err) { + function (err) { expect(err).to.not.exist; expect(client.authenticated).to.be.true; done(); } ); }); - it('should fail with xoauth2 object', function(done) { + it('should fail with xoauth2 object', function (done) { expect(client.authenticated).to.be.false; client.login( { @@ -760,15 +755,15 @@ describe('SMTP-Connection Tests', function() { accessUrl: 'http://localhost:' + XOAUTH_PORT }) }, - function(err) { + function (err) { expect(err).to.exist; expect(client.authenticated).to.be.false; done(); } ); }); - it('should fail with invalid xoauth2 response', function(done) { + it('should fail with invalid xoauth2 response', function (done) { expect(client.authenticated).to.be.false; let oauth2 = new XOAuth2({ @@ -788,7 +783,7 @@ describe('SMTP-Connection Tests', function() { user: 'testuser', oauth2 }, - function(err) { + function (err) { expect(err).to.exist; expect(client.authenticated).to.be.false; @@ -799,9 +794,9 @@ describe('SMTP-Connection Tests', function() { }); }); - describe('custom login', function() { + describe('custom login', function () { let customClient; - beforeEach(function(done) { + beforeEach(function (done) { customClient = new SMTPConnection({ port: PORT_NUMBER, logger: false, @@ -824,12 +819,12 @@ describe('SMTP-Connection Tests', function() { customClient.connect(done); }); - afterEach(function(done) { + afterEach(function (done) { customClient.close(); done(); }); - it('should login', function(done) { + it('should login', function (done) { expect(customClient.authenticated).to.be.false; customClient.login( { @@ -840,7 +835,7 @@ describe('SMTP-Connection Tests', function() { pass: 'testpass' } }, - function(err) { + function (err) { expect(err).to.not.exist; expect(customClient.authenticated).to.be.true; done(); @@ -849,17 +844,17 @@ describe('SMTP-Connection Tests', function() { }); }); - describe('Send without PIPELINING', function() { - beforeEach(function(done) { - client.on('end', function() { + describe('Send without PIPELINING', function () { + beforeEach(function (done) { + client.on('end', function () { client = new SMTPConnection({ port: PORT_NUMBER, logger: false, debug: false }); // disable PIPELINING server.options.hidePIPELINING = true; - client.connect(function() { + client.connect(function () { client.login( { user: 'testuser', @@ -868,7 +863,7 @@ describe('SMTP-Connection Tests', function() { pass: 'testpass' } }, - function(err) { + function (err) { expect(err).to.not.exist; // enable PIPELINING server.options.hidePIPELINING = false; @@ -880,14 +875,14 @@ describe('SMTP-Connection Tests', function() { client.close(); }); - it('should send only to valid recipients without PIPELINING', function(done) { + it('should send only to valid recipients without PIPELINING', function (done) { client.send( { from: 'test@valid.sender', to: ['test1@valid.recipient', 'test2@invalid.recipient', 'test3@valid.recipient'] }, 'test', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info).to.deep.equal({ accepted: ['test1@valid.recipient', 'test3@valid.recipient'], @@ -905,8 +900,8 @@ describe('SMTP-Connection Tests', function() { }); }); - describe('Send messages', function() { - beforeEach(function(done) { + describe('Send messages', function () { + beforeEach(function (done) { client.login( { user: 'testuser', @@ -915,21 +910,21 @@ describe('SMTP-Connection Tests', function() { pass: 'testpass' } }, - function(err) { + function (err) { expect(err).to.not.exist; done(); } ); }); - it('should send message', function(done) { + it('should send message', function (done) { client.send( { from: 'test@valid.sender', to: 'test@valid.recipient' }, 'test', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info).to.deep.equal({ accepted: ['test@valid.recipient'], @@ -944,14 +939,14 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should send multiple messages', function(done) { + it('should send multiple messages', function (done) { client.send( { from: 'test@valid.sender', to: 'test@valid.recipient' }, 'test', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info).to.deep.equal({ accepted: ['test@valid.recipient'], @@ -961,7 +956,7 @@ describe('SMTP-Connection Tests', function() { messageSize: info.messageSize, response: '250 OK: message queued' }); - client.reset(function(err) { + client.reset(function (err) { expect(err).to.not.exist; client.send( @@ -970,7 +965,7 @@ describe('SMTP-Connection Tests', function() { to: 'test2@valid.recipient' }, 'test2', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info).to.deep.equal({ accepted: ['test2@valid.recipient'], @@ -988,14 +983,14 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should send only to valid recipients', function(done) { + it('should send only to valid recipients', function (done) { client.send( { from: 'test@valid.sender', to: ['test1@valid.recipient', 'test2@invalid.recipient', 'test3@valid.recipient'] }, 'test', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info).to.deep.equal({ accepted: ['test1@valid.recipient', 'test3@valid.recipient'], @@ -1012,14 +1007,14 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should reject all recipients', function(done) { + it('should reject all recipients', function (done) { client.send( { from: 'test@valid.sender', to: ['test1@invalid.recipient', 'test2@invalid.recipient', 'test3@invalid.recipient'] }, 'test', - function(err, info) { + function (err, info) { expect(err).to.exist; expect(info).to.not.exist; expect(err.rejected).to.deep.equal(['test1@invalid.recipient', 'test2@invalid.recipient', 'test3@invalid.recipient']); @@ -1029,47 +1024,47 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should reject too large SIZE arguments', function(done) { + it('should reject too large SIZE arguments', function (done) { client.send( { from: 'test2@valid.sender', to: 'test2@valid.recipient', size: 1024 * 1024 }, 'test', - function(err, info) { + function (err, info) { expect(err).to.exist; expect(info).to.not.exist; done(); } ); }); - it('should reject too large message', function(done) { + it('should reject too large message', function (done) { client.send( { from: 'test2@valid.sender', to: 'test2@valid.recipient', size: 70 * 1024 }, 'test', - function(err, info) { + function (err, info) { expect(err).to.exist; expect(info).to.not.exist; done(); } ); }); - it('should declare SIZE', function(done) { + it('should declare SIZE', function (done) { client.send( { from: 'test2@valid.sender', to: 'test2@valid.recipient', size: 10 * 1024 }, 'test', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info).to.deep.equal({ accepted: ['test2@valid.recipient'], @@ -1084,7 +1079,7 @@ describe('SMTP-Connection Tests', function() { ); }); - it('lmtp should send only to valid recipients', function(done) { + it('lmtp should send only to valid recipients', function (done) { lmtpClient.send( { from: 'test@valid.sender', @@ -1098,7 +1093,7 @@ describe('SMTP-Connection Tests', function() { ] }, 'test', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info.accepted).to.deep.equal(['test3@valid.recipient', 'test5@valid.recipient']); expect(info.rejected).to.deep.equal([ @@ -1113,14 +1108,14 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should send using SMTPUTF8', function(done) { + it('should send using SMTPUTF8', function (done) { client.send( { from: 'test@valid.sender', to: ['test1@valid.recipient', 'test2@invalid.recipient', 'test3õ@valid.recipient'] }, 'test', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info).to.deep.equal({ accepted: ['test1@valid.recipient', 'test3õ@valid.recipient'], @@ -1136,15 +1131,15 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should send using 8BITMIME', function(done) { + it('should send using 8BITMIME', function (done) { client.send( { use8BitMime: true, from: 'test@valid.sender', to: ['test1@valid.recipient', 'test2@invalid.recipient', 'test3õ@valid.recipient'] }, 'õõõõ', - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info).to.deep.equal({ accepted: ['test1@valid.recipient', 'test3õ@valid.recipient'], @@ -1160,73 +1155,73 @@ describe('SMTP-Connection Tests', function() { ); }); - it('should receive error for 8-bit content without 8BITMIME declaration', function(done) { + it('should receive error for 8-bit content without 8BITMIME declaration', function (done) { client.send( { use8BitMime: false, from: 'test@valid.sender', to: ['test1@valid.recipient', 'test2@invalid.recipient', 'test3õ@valid.recipient'] }, 'õõõõ', - function(err) { + function (err) { expect(/8 bit content not allowed/.test(err.message)).to.be.true; done(); } ); }); - it('should return error for invalidly formatted recipients', function(done) { + it('should return error for invalidly formatted recipients', function (done) { client.send( { from: 'test@valid.sender', to: ['test@valid.recipient', '"address\r\n with folding"@valid.recipient'] }, 'test', - function(err) { + function (err) { expect(/^Invalid recipient/.test(err.message)).to.be.true; done(); } ); }); - it('should return error for no valid recipients', function(done) { + it('should return error for no valid recipients', function (done) { client.send( { from: 'test@valid.sender', to: ['test1@invalid.recipient', 'test2@invalid.recipient', 'test3@invalid.recipient'] }, 'test', - function(err) { + function (err) { expect(err).to.exist; done(); } ); }); - it('should return error for invalid sender', function(done) { + it('should return error for invalid sender', function (done) { client.send( { from: 'test@invalid.sender', to: 'test@valid.recipient' }, 'test', - function(err) { + function (err) { expect(err).to.exist; done(); } ); }); - it('should send message string', function(done) { + it('should send message string', function (done) { let chunks = [], message = new Array(1024).join('teretere, vana kere\n'); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); server.removeAllListeners('dataReady'); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n')); callback(null, 'ABC1'); @@ -1238,30 +1233,25 @@ describe('SMTP-Connection Tests', function() { to: 'test@valid.recipient' }, message, - function(err) { + function (err) { expect(err).to.not.exist; done(); } ); }); - it('should send message buffer', function(done) { + it('should send message buffer', function (done) { let chunks = [], message = Buffer.from(new Array(1024).join('teretere, vana kere\n')); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); server.removeAllListeners('dataReady'); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); - expect(body.toString()).to.equal( - message - .toString() - .trim() - .replace(/\n/g, '\r\n') - ); + expect(body.toString()).to.equal(message.toString().trim().replace(/\n/g, '\r\n')); callback(null, 'ABC1'); }); @@ -1271,31 +1261,26 @@ describe('SMTP-Connection Tests', function() { to: 'test@valid.recipient' }, message, - function(err) { + function (err) { expect(err).to.not.exist; done(); } ); }); - it('should send message stream', function(done) { + it('should send message stream', function (done) { let chunks = [], fname = __dirname + '/../../LICENSE', message = fs.readFileSync(fname, 'utf-8'); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); server.removeAllListeners('dataReady'); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); - expect(body.toString()).to.equal( - message - .toString() - .trim() - .replace(/\n/g, '\r\n') - ); + expect(body.toString()).to.equal(message.toString().trim().replace(/\n/g, '\r\n')); callback(null, 'ABC1'); }); @@ -1305,7 +1290,7 @@ describe('SMTP-Connection Tests', function() { to: 'test@valid.recipient' }, fs.createReadStream(fname), - function(err) { + function (err) { expect(err).to.not.exist; done(); } @@ -1316,11 +1301,11 @@ describe('SMTP-Connection Tests', function() { }); function proxyConnect(port, host, destinationPort, destinationHost, callback) { - let socket = net.connect(port, host, function() { + let socket = net.connect(port, host, function () { socket.write('CONNECT ' + destinationHost + ':' + destinationPort + ' HTTP/1.1\r\n\r\n'); let headers = ''; - let onSocketData = function(chunk) { + let onSocketData = function (chunk) { let match; let remainder; @@ -1339,7 +1324,7 @@ function proxyConnect(port, host, destinationPort, destinationHost, callback) { socket.on('data', onSocketData); }); - socket.on('error', function(err) { + socket.on('error', function (err) { expect(err).to.not.exist; }); }
test/smtp-connection/xoauth2-mock-server.js+6 −6 modified@@ -4,7 +4,7 @@ const http = require('http'); const crypto = require('crypto'); const querystring = require('querystring'); -module.exports = function(options) { +module.exports = function (options) { return new OAuthServer(options); }; @@ -17,7 +17,7 @@ function OAuthServer(options) { this.options.expiresIn = Number(this.options.expiresIn) || 3600; } -OAuthServer.prototype.addUser = function(username, refreshToken) { +OAuthServer.prototype.addUser = function (username, refreshToken) { let user = { username, refreshToken: refreshToken || crypto.randomBytes(10).toString('base64') @@ -29,7 +29,7 @@ OAuthServer.prototype.addUser = function(username, refreshToken) { return this.generateAccessToken(user.refreshToken); }; -OAuthServer.prototype.generateAccessToken = function(refreshToken) { +OAuthServer.prototype.generateAccessToken = function (refreshToken) { let username = this.tokens[refreshToken], accessToken = crypto.randomBytes(10).toString('base64'); @@ -53,15 +53,15 @@ OAuthServer.prototype.generateAccessToken = function(refreshToken) { }; }; -OAuthServer.prototype.validateAccessToken = function(username, accessToken) { +OAuthServer.prototype.validateAccessToken = function (username, accessToken) { if (!this.users[username] || this.users[username].accessToken !== accessToken || this.users[username].expiresIn < Date.now()) { return false; } else { return true; } }; -OAuthServer.prototype.start = function(callback) { +OAuthServer.prototype.start = function (callback) { this.server = http.createServer((req, res) => { let data = [], datalen = 0; @@ -88,6 +88,6 @@ OAuthServer.prototype.start = function(callback) { this.server.listen(this.options.port, callback); }; -OAuthServer.prototype.stop = function(callback) { +OAuthServer.prototype.stop = function (callback) { this.server.close(callback); };
test/smtp-pool/smtp-pool-test.js+71 −71 modified@@ -41,18 +41,18 @@ class MockBuilder { } } -describe('SMTP Pool Tests', function() { +describe('SMTP Pool Tests', function () { this.timeout(100 * 1000); //eslint-disable-line no-invalid-this let server; - beforeEach(function(done) { + beforeEach(function (done) { server = new SMTPServer({ authMethods: ['PLAIN', 'XOAUTH2'], disabledCommands: ['STARTTLS'], onData(stream, session, callback) { - stream.on('data', function() {}); + stream.on('data', function () {}); stream.on('end', callback); }, @@ -95,17 +95,17 @@ describe('SMTP Pool Tests', function() { server.listen(PORT_NUMBER, done); }); - afterEach(function(done) { + afterEach(function (done) { server.close(done); }); - it('Should expose version number', function() { + it('Should expose version number', function () { let pool = new SMTPPool(); expect(pool.name).to.exist; expect(pool.version).to.exist; }); - it('Should detect wellknown data', function() { + it('Should detect wellknown data', function () { let pool = new SMTPPool({ service: 'google mail' }); @@ -114,7 +114,7 @@ describe('SMTP Pool Tests', function() { expect(pool.options.secure).to.be.true; }); - it('should send mail', function(done) { + it('should send mail', function (done) { let pool = new SMTPPool({ port: PORT_NUMBER, auth: { @@ -127,12 +127,12 @@ describe('SMTP Pool Tests', function() { let message = new Array(1024).join('teretere, vana kere\n'); - server.onData = function(stream, session, callback) { + server.onData = function (stream, session, callback) { let chunks = []; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { chunks.push(chunk); }); - stream.on('end', function() { + stream.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n') + '\r\n'); callback(); @@ -150,24 +150,24 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.not.exist; pool.close(); done(); } ); }); - it('should send multiple mails', function(done) { + it('should send multiple mails', function (done) { let pool = new SMTPPool('smtp://testuser:testpass@localhost:' + PORT_NUMBER + '/?logger=false'); let message = new Array(10 * 1024).join('teretere, vana kere\n'); - server.onData = function(stream, session, callback) { + server.onData = function (stream, session, callback) { let chunks = []; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { chunks.push(chunk); }); - stream.on('end', function() { + stream.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n') + '\r\n'); callback(); @@ -186,7 +186,7 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.not.exist; callback(); } @@ -195,12 +195,12 @@ describe('SMTP Pool Tests', function() { let total = 100; let returned = 0; - let cb = function() { + let cb = function () { let sent = 0; if (++returned === total) { expect(pool._connections.length).to.be.above(1); - pool._connections.forEach(function(conn) { + pool._connections.forEach(function (conn) { expect(conn.messages).to.be.above(1); sent += conn.messages; }); @@ -216,7 +216,7 @@ describe('SMTP Pool Tests', function() { } }); - it('should tolerate connection errors', function(done) { + it('should tolerate connection errors', function (done) { let pool = new SMTPPool({ port: PORT_NUMBER, auth: { @@ -227,12 +227,12 @@ describe('SMTP Pool Tests', function() { }); let message = new Array(10 * 1024).join('teretere, vana kere\n'); - server.onData = function(stream, session, callback) { + server.onData = function (stream, session, callback) { let chunks = []; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { chunks.push(chunk); }); - stream.on('end', function() { + stream.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n') + '\r\n'); callback(); @@ -254,7 +254,7 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { if (isErr) { expect(err).to.exist; } else { @@ -268,7 +268,7 @@ describe('SMTP Pool Tests', function() { let total = 100; let returned = 0; - let cb = function() { + let cb = function () { if (++returned === total) { pool.close(); return done(); @@ -279,7 +279,7 @@ describe('SMTP Pool Tests', function() { } }); - it('should tolerate idle connections and re-assign messages to other connections', function(done) { + it('should tolerate idle connections and re-assign messages to other connections', function (done) { let pool = new SMTPPool({ port: PORT_NUMBER, auth: { @@ -294,22 +294,22 @@ describe('SMTP Pool Tests', function() { let sentMessages = 0; let killedConnections = false; - server.onData = function(stream, session, callback) { + server.onData = function (stream, session, callback) { let callCallback = true; - stream.on('data', function() { + stream.on('data', function () { // If we hit half the messages, simulate the server closing connections // that are open for long time if (!killedConnections && sentMessages === total / 2) { killedConnections = true; callCallback = false; - server.connections.forEach(function(connection) { + server.connections.forEach(function (connection) { connection._socket.end(); }); } }); - stream.on('end', function() { + stream.on('end', function () { if (callCallback) { sentMessages += 1; return callback(); @@ -329,7 +329,7 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { if (err) { expect(err.message).to.equal('Connection closed unexpectedly'); } @@ -342,7 +342,7 @@ describe('SMTP Pool Tests', function() { // When we wait a bit.. the server will kill the "idle" connections // so that we can ensure the pool will handle it properly let returned = 0; - let cb = function() { + let cb = function () { returned++; if (returned === total) { @@ -362,7 +362,7 @@ describe('SMTP Pool Tests', function() { sendHalfBulk(); }); - it('should call back with connection errors to senders having messages in flight', function(done) { + it('should call back with connection errors to senders having messages in flight', function (done) { let pool = new SMTPPool({ maxConnections: 1, socketTimeout: 200, @@ -386,7 +386,7 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { expect(err).not.to.exist; } ); @@ -402,24 +402,24 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.exist; pool.close(); done(); } ); }); - it('should not send more then allowed for one connection', function(done) { + it('should not send more then allowed for one connection', function (done) { let pool = new SMTPPool('smtp://testuser:testpass@localhost:' + PORT_NUMBER + '/?maxConnections=1&maxMessages=5&logger=false'); let message = new Array(10 * 1024).join('teretere, vana kere\n'); - server.onData = function(stream, session, callback) { + server.onData = function (stream, session, callback) { let chunks = []; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { chunks.push(chunk); }); - stream.on('end', function() { + stream.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n') + '\r\n'); callback(); @@ -438,7 +438,7 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.not.exist; callback(); } @@ -447,7 +447,7 @@ describe('SMTP Pool Tests', function() { let total = 100; let returned = 0; - let cb = function() { + let cb = function () { if (++returned === total) { expect(pool._connections.length).to.be.equal(1); expect(pool._connections[0].messages).to.be.below(6); @@ -460,7 +460,7 @@ describe('SMTP Pool Tests', function() { } }); - it('should send multiple mails with rate limit', function(done) { + it('should send multiple mails with rate limit', function (done) { let pool = new SMTPPool({ port: PORT_NUMBER, auth: { @@ -474,12 +474,12 @@ describe('SMTP Pool Tests', function() { let message = 'teretere, vana kere\n'; let startTime = Date.now(); - server.onData = function(stream, session, callback) { + server.onData = function (stream, session, callback) { let chunks = []; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { chunks.push(chunk); }); - stream.on('end', function() { + stream.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n') + '\r\n'); callback(); @@ -498,7 +498,7 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.not.exist; callback(); } @@ -507,7 +507,7 @@ describe('SMTP Pool Tests', function() { let total = 5000; let returned = 0; - let cb = function() { + let cb = function () { if (++returned === total) { let endTime = Date.now(); expect(endTime - startTime).to.be.at.least(24000); @@ -518,7 +518,7 @@ describe('SMTP Pool Tests', function() { }; let i = 0; - let send = function() { + let send = function () { if (i++ >= total) { return; } @@ -529,16 +529,16 @@ describe('SMTP Pool Tests', function() { send(); }); - it('should return pending messages once closed', function(done) { + it('should return pending messages once closed', function (done) { let pool = new SMTPPool('smtp://testuser:testpass@localhost:' + PORT_NUMBER + '/?maxConnections=1&logger=false'); let message = new Array(10 * 1024).join('teretere, vana kere\n'); - server.onData = function(stream, session, callback) { + server.onData = function (stream, session, callback) { let chunks = []; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { chunks.push(chunk); }); - stream.on('end', function() { + stream.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n') + '\r\n'); callback(); @@ -557,7 +557,7 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.exist; callback(); } @@ -566,7 +566,7 @@ describe('SMTP Pool Tests', function() { let total = 100; let returned = 0; - let cb = function() { + let cb = function () { if (++returned === total) { return done(); } @@ -577,16 +577,16 @@ describe('SMTP Pool Tests', function() { pool.close(); }); - it('should emit idle for free slots in the pool', function(done) { + it('should emit idle for free slots in the pool', function (done) { let pool = new SMTPPool('smtp://testuser:testpass@localhost:' + PORT_NUMBER + '/?logger=false'); let message = new Array(10 * 1024).join('teretere, vana kere\n'); - server.onData = function(stream, session, callback) { + server.onData = function (stream, session, callback) { let chunks = []; - stream.on('data', function(chunk) { + stream.on('data', function (chunk) { chunks.push(chunk); }); - stream.on('end', function() { + stream.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n') + '\r\n'); callback(); @@ -611,23 +611,23 @@ describe('SMTP Pool Tests', function() { let total = 100; let returned = 0; - let cb = function() { + let cb = function () { if (++returned === total) { pool.close(); return done(); } }; let i = 0; - pool.on('idle', function() { - setTimeout(function() { + pool.on('idle', function () { + setTimeout(function () { while (i < total && pool.isIdle()) { i++; sendMessage(cb); } if (i > 50) { // kill all connections. We should still end up with the same amount of callbacks - setImmediate(function() { + setImmediate(function () { for (let j = 5 - 1; j >= 0; j--) { if (pool._connections[j] && pool._connections[j].connection) { pool._connections[j].connection._socket.emit('error', new Error('TESTERROR')); @@ -639,17 +639,17 @@ describe('SMTP Pool Tests', function() { }); }); - it('Should login and send mail using proxied socket', function(done) { + it('Should login and send mail using proxied socket', function (done) { let pool = new SMTPPool({ url: 'smtp:testuser:testpass@www.example.com:1234', logger: false, getSocket(options, callback) { let socket = net.connect(PORT_NUMBER, 'localhost'); - let errHandler = function(err) { + let errHandler = function (err) { callback(err); }; socket.on('error', errHandler); - socket.on('connect', function() { + socket.on('connect', function () { socket.removeListener('error', errHandler); callback(null, { connection: socket @@ -660,11 +660,11 @@ describe('SMTP Pool Tests', function() { let chunks = [], message = new Array(1024).join('teretere, vana kere\n'); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n') + '\r\n'); callback(null, true); @@ -681,35 +681,35 @@ describe('SMTP Pool Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.not.exist; pool.close(); return done(); } ); }); - it('Should verify connection with success', function(done) { + it('Should verify connection with success', function (done) { let client = new SMTPPool({ url: 'smtp:testuser:testpass@localhost:' + PORT_NUMBER, logger: false }); - client.verify(function(err, success) { + client.verify(function (err, success) { expect(err).to.not.exist; expect(success).to.be.true; client.close(); done(); }); }); - it('Should not verify connection', function(done) { + it('Should not verify connection', function (done) { let client = new SMTPPool({ url: 'smtp:testuser:testpass@localhost:999' + PORT_NUMBER, logger: false }); - client.verify(function(err) { + client.verify(function (err) { expect(err).to.exist; client.close(); done();
test/smtp-transport/smtp-tranport-test.js+39 −39 modified@@ -41,18 +41,18 @@ class MockBuilder { } } -describe('SMTP Transport Tests', function() { +describe('SMTP Transport Tests', function () { this.timeout(10000); // eslint-disable-line no-invalid-this - describe('Anonymous sender tests', function() { + describe('Anonymous sender tests', function () { let server, failingServer; - beforeEach(function(done) { + beforeEach(function (done) { server = new SMTPServer({ disabledCommands: ['STARTTLS', 'AUTH'], onData(stream, session, callback) { - stream.on('data', function() {}); + stream.on('data', function () {}); stream.on('end', callback); }, @@ -108,17 +108,17 @@ describe('SMTP Transport Tests', function() { }); }); - afterEach(function(done) { + afterEach(function (done) { server.close(() => failingServer.close(done)); }); - it('Should expose version number', function() { + it('Should expose version number', function () { let client = new SMTPTransport(); expect(client.name).to.exist; expect(client.version).to.exist; }); - it('Should detect wellknown data', function() { + it('Should detect wellknown data', function () { let client = new SMTPTransport({ service: 'google mail', logger: false @@ -128,7 +128,7 @@ describe('SMTP Transport Tests', function() { expect(client.options.secure).to.be.true; }); - it('Should fail envelope', function(done) { + it('Should fail envelope', function (done) { let client = new SMTPTransport({ port: PORT_NUMBER, logger: false @@ -145,14 +145,14 @@ describe('SMTP Transport Tests', function() { 'test' ) }, - function(err) { + function (err) { expect(err.code).to.equal('EENVELOPE'); done(); } ); }); - it('Should not fail auth', function(done) { + it('Should not fail auth', function (done) { let client = new SMTPTransport({ port: PORT_NUMBER, auth: { @@ -172,14 +172,14 @@ describe('SMTP Transport Tests', function() { 'message' ) }, - function(err) { + function (err) { expect(err).to.not.exist; done(); } ); }); - it('Should fail auth if forceAuth=true', function(done) { + it('Should fail auth if forceAuth=true', function (done) { let client = new SMTPTransport({ port: PORT_NUMBER, auth: { @@ -200,23 +200,23 @@ describe('SMTP Transport Tests', function() { 'message' ) }, - function(err) { + function (err) { expect(err.code).to.equal('EAUTH'); done(); } ); }); - it('Should send mail', function(done) { + it('Should send mail', function (done) { let client = new SMTPTransport('smtp:localhost:' + PORT_NUMBER + '?logger=false'); let chunks = [], message = new Array(1024).join('teretere, vana kere\n'); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n')); callback(null, true); @@ -233,23 +233,23 @@ describe('SMTP Transport Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.not.exist; done(); } ); }); - it('Should recover unexpeced close during transmission', function(done) { + it('Should recover unexpeced close during transmission', function (done) { let client = new SMTPTransport('smtp:localhost:' + (PORT_NUMBER + 1) + '?logger=false'); let chunks = [], message = new Array(1024).join('teretere, vana kere\n'); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n')); callback(null, true); @@ -266,24 +266,24 @@ describe('SMTP Transport Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.exist; done(); } ); }); }); - describe('Authenticated sender tests', function() { + describe('Authenticated sender tests', function () { let server; - beforeEach(function(done) { + beforeEach(function (done) { server = new SMTPServer({ authMethods: ['PLAIN', 'XOAUTH2'], disabledCommands: ['STARTTLS'], onData(stream, session, callback) { - stream.on('data', function() {}); + stream.on('data', function () {}); stream.on('end', callback); }, @@ -323,23 +323,23 @@ describe('SMTP Transport Tests', function() { server.listen(PORT_NUMBER, done); }); - afterEach(function(done) { + afterEach(function (done) { server.close(done); }); - it('Should login and send mail', function(done) { + it('Should login and send mail', function (done) { let client = new SMTPTransport({ url: 'smtp:testuser:testpass@localhost:' + PORT_NUMBER, logger: false }); let chunks = [], message = new Array(1024).join('teretere, vana kere\n'); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n')); callback(null, true); @@ -356,49 +356,49 @@ describe('SMTP Transport Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.not.exist; done(); } ); }); - it('Should verify connection with success', function(done) { + it('Should verify connection with success', function (done) { let client = new SMTPTransport({ url: 'smtp:testuser:testpass@localhost:' + PORT_NUMBER, logger: false }); - client.verify(function(err, success) { + client.verify(function (err, success) { expect(err).to.not.exist; expect(success).to.be.true; done(); }); }); - it('Should not verify connection', function(done) { + it('Should not verify connection', function (done) { let client = new SMTPTransport({ url: 'smtp:testuser:testpass@localhost:999' + PORT_NUMBER, logger: false }); - client.verify(function(err) { + client.verify(function (err) { expect(err).to.exist; done(); }); }); - it('Should login and send mail using proxied socket', function(done) { + it('Should login and send mail using proxied socket', function (done) { let client = new SMTPTransport({ url: 'smtp:testuser:testpass@www.example.com:1234', logger: false, getSocket(options, callback) { let socket = net.connect(PORT_NUMBER, 'localhost'); - let errHandler = function(err) { + let errHandler = function (err) { callback(err); }; socket.on('error', errHandler); - socket.on('connect', function() { + socket.on('connect', function () { socket.removeListener('error', errHandler); callback(null, { connection: socket @@ -409,11 +409,11 @@ describe('SMTP Transport Tests', function() { let chunks = [], message = new Array(1024).join('teretere, vana kere\n'); - server.on('data', function(connection, chunk) { + server.on('data', function (connection, chunk) { chunks.push(chunk); }); - server.on('dataReady', function(connection, callback) { + server.on('dataReady', function (connection, callback) { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n')); callback(null, true); @@ -430,7 +430,7 @@ describe('SMTP Transport Tests', function() { message ) }, - function(err) { + function (err) { expect(err).to.not.exist; done(); }
test/stream-transport/stream-transport-test.js+16 −16 modified@@ -35,17 +35,17 @@ class MockBuilder { } } -describe('Stream Transport Tests', function() { +describe('Stream Transport Tests', function () { this.timeout(10000); // eslint-disable-line no-invalid-this - it('Should expose version number', function() { + it('Should expose version number', function () { let client = new StreamTransport(); expect(client.name).to.exist; expect(client.version).to.exist; }); - describe('Send as stream', function() { - it('Should send mail using unix newlines', function(done) { + describe('Send as stream', function () { + it('Should send mail using unix newlines', function (done) { let client = new StreamTransport(); let chunks = [], message = new Array(100).join('teretere\r\nvana kere\r\n'); @@ -61,7 +61,7 @@ describe('Stream Transport Tests', function() { message ) }, - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info.envelope).to.deep.equal({ @@ -71,11 +71,11 @@ describe('Stream Transport Tests', function() { expect(info.messageId).to.equal('<test>'); - info.message.on('data', function(chunk) { + info.message.on('data', function (chunk) { chunks.push(chunk); }); - info.message.on('end', function() { + info.message.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.replace(/\r\n/g, '\n')); done(); @@ -84,7 +84,7 @@ describe('Stream Transport Tests', function() { ); }); - it('Should send mail using windows newlines', function(done) { + it('Should send mail using windows newlines', function (done) { let client = new StreamTransport({ newline: 'windows' }); @@ -102,14 +102,14 @@ describe('Stream Transport Tests', function() { message ) }, - function(err, info) { + function (err, info) { expect(err).to.not.exist; - info.message.on('data', function(chunk) { + info.message.on('data', function (chunk) { chunks.push(chunk); }); - info.message.on('end', function() { + info.message.on('end', function () { let body = Buffer.concat(chunks); expect(body.toString()).to.equal(message.replace(/\n/g, '\r\n')); done(); @@ -119,8 +119,8 @@ describe('Stream Transport Tests', function() { }); }); - describe('Send as buffer', function() { - it('Should send mail using unix newlines', function(done) { + describe('Send as buffer', function () { + it('Should send mail using unix newlines', function (done) { let client = new StreamTransport({ buffer: true }); @@ -137,7 +137,7 @@ describe('Stream Transport Tests', function() { message ) }, - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info.message.toString()).to.equal(message.replace(/\r\n/g, '\n')); @@ -146,7 +146,7 @@ describe('Stream Transport Tests', function() { ); }); - it('Should send mail using windows newlines', function(done) { + it('Should send mail using windows newlines', function (done) { let client = new StreamTransport({ newline: 'windows', buffer: true @@ -164,7 +164,7 @@ describe('Stream Transport Tests', function() { message ) }, - function(err, info) { + function (err, info) { expect(err).to.not.exist; expect(info.message.toString()).to.equal(message.replace(/\n/g, '\r\n'));
test/well-known/well-known-test.js+6 −6 modified@@ -9,33 +9,33 @@ const wellKnown = require('../../lib/well-known'); chai.config.includeStack = true; -describe('Well-Known Services Tests', function() { - describe('#wellKnown', function() { - it('Should find by key', function() { +describe('Well-Known Services Tests', function () { + describe('#wellKnown', function () { + it('Should find by key', function () { expect(wellKnown('Gmail')).to.deep.equal({ host: 'smtp.gmail.com', port: 465, secure: true }); }); - it('Should find by alias', function() { + it('Should find by alias', function () { expect(wellKnown('Google Mail')).to.deep.equal({ host: 'smtp.gmail.com', port: 465, secure: true }); }); - it('Should find by domain', function() { + it('Should find by domain', function () { expect(wellKnown('GoogleMail.com')).to.deep.equal({ host: 'smtp.gmail.com', port: 465, secure: true }); }); - it('Should find no match', function() { + it('Should find no match', function () { expect(wellKnown('zzzzzz')).to.be.false; }); });
test/xoauth2/server.js+6 −6 modified@@ -6,7 +6,7 @@ const http = require('http'); const crypto = require('crypto'); const querystring = require('querystring'); -module.exports = function(options) { +module.exports = function (options) { return new OAuthServer(options); }; @@ -19,7 +19,7 @@ function OAuthServer(options) { this.options.expiresIn = Number(this.options.expiresIn) || 3600; } -OAuthServer.prototype.addUser = function(username, refreshToken) { +OAuthServer.prototype.addUser = function (username, refreshToken) { let user = { username, refreshToken: refreshToken || crypto.randomBytes(10).toString('base64') @@ -31,7 +31,7 @@ OAuthServer.prototype.addUser = function(username, refreshToken) { return this.generateAccessToken(user.refreshToken); }; -OAuthServer.prototype.generateAccessToken = function(refreshToken) { +OAuthServer.prototype.generateAccessToken = function (refreshToken) { let username = this.tokens[refreshToken]; let accessToken = crypto.randomBytes(10).toString('base64'); @@ -55,15 +55,15 @@ OAuthServer.prototype.generateAccessToken = function(refreshToken) { }; }; -OAuthServer.prototype.validateAccessToken = function(username, accessToken) { +OAuthServer.prototype.validateAccessToken = function (username, accessToken) { if (!this.users[username] || this.users[username].accessToken !== accessToken || this.users[username].expiresIn < Date.now()) { return false; } else { return true; } }; -OAuthServer.prototype.start = function(callback) { +OAuthServer.prototype.start = function (callback) { this.server = http.createServer((req, res) => { let data = []; let datalen = 0; @@ -92,6 +92,6 @@ OAuthServer.prototype.start = function(callback) { this.server.listen(this.options.port, callback); }; -OAuthServer.prototype.stop = function(callback) { +OAuthServer.prototype.stop = function (callback) { this.server.close(callback); };
test/xoauth2/xoauth2-test.js+22 −22 modified@@ -10,29 +10,29 @@ const mockServer = require('./server'); chai.config.includeStack = true; -describe('XOAuth2 tests', function() { +describe('XOAuth2 tests', function () { this.timeout(10000); let server; let users = {}; let XOAUTH_PORT = 8993; - beforeEach(function(done) { + beforeEach(function (done) { server = mockServer({ port: XOAUTH_PORT, - onUpdate: function(username, accessToken) { + onUpdate: function (username, accessToken) { users[username] = accessToken; } }); server.addUser('test@example.com', 'saladus'); server.start(done); }); - afterEach(function(done) { + afterEach(function (done) { server.stop(done); }); - it('should get an existing access token', function(done) { + it('should get an existing access token', function (done) { let xoauth2 = new XOAuth2({ user: 'test@example.com', clientId: '{Client ID}', @@ -43,14 +43,14 @@ describe('XOAuth2 tests', function() { timeout: 3600 }); - xoauth2.getToken(false, function(err, accessToken) { + xoauth2.getToken(false, function (err, accessToken) { expect(err).to.not.exist; expect(accessToken).to.equal('abc'); done(); }); }); - it('should convert access token to XOAuth2 token', function() { + it('should convert access token to XOAuth2 token', function () { let xoauth2 = new XOAuth2({ user: 'test@example.com', accessToken: 'abc' @@ -60,7 +60,7 @@ describe('XOAuth2 tests', function() { expect(xoauth2.buildXOAuth2Token('bbb')).to.equal('dXNlcj10ZXN0QGV4YW1wbGUuY29tAWF1dGg9QmVhcmVyIGJiYgEB'); }); - it('should get an existing access token, no timeout', function(done) { + it('should get an existing access token, no timeout', function (done) { let xoauth2 = new XOAuth2({ user: 'test@example.com', clientId: '{Client ID}', @@ -70,14 +70,14 @@ describe('XOAuth2 tests', function() { accessToken: 'abc' }); - xoauth2.getToken(false, function(err, accessToken) { + xoauth2.getToken(false, function (err, accessToken) { expect(err).to.not.exist; expect(accessToken).to.equal('abc'); done(); }); }); - it('should generate a fresh access token', function(done) { + it('should generate a fresh access token', function (done) { let xoauth2 = new XOAuth2({ user: 'test@example.com', clientId: '{Client ID}', @@ -87,14 +87,14 @@ describe('XOAuth2 tests', function() { timeout: 3600 }); - xoauth2.getToken(false, function(err, accessToken) { + xoauth2.getToken(false, function (err, accessToken) { expect(err).to.not.exist; expect(accessToken).to.equal(users['test@example.com']); done(); }); }); - it('should generate a fresh access token with custom method', function(done) { + it('should generate a fresh access token with custom method', function (done) { let xoauth2 = new XOAuth2({ user: 'test@example.com', clientId: '{Client ID}', @@ -107,14 +107,14 @@ describe('XOAuth2 tests', function() { } }); - xoauth2.getToken(false, function(err, accessToken) { + xoauth2.getToken(false, function (err, accessToken) { expect(err).to.not.exist; expect(accessToken).to.equal('zzz'); done(); }); }); - it('should fail generating a fresh access token with custom method', function(done) { + it('should fail generating a fresh access token with custom method', function (done) { let xoauth2 = new XOAuth2({ user: 'test@example.com', clientId: '{Client ID}', @@ -127,14 +127,14 @@ describe('XOAuth2 tests', function() { } }); - xoauth2.getToken(false, function(err, accessToken) { + xoauth2.getToken(false, function (err, accessToken) { expect(err).to.exist; expect(accessToken).to.not.exist; done(); }); }); - it('should generate a fresh access token after timeout', function(done) { + it('should generate a fresh access token after timeout', function (done) { let xoauth2 = new XOAuth2({ user: 'test@example.com', clientId: '{Client ID}', @@ -145,16 +145,16 @@ describe('XOAuth2 tests', function() { timeout: 1 }); - setTimeout(function() { - xoauth2.getToken(false, function(err, accessToken) { + setTimeout(function () { + xoauth2.getToken(false, function (err, accessToken) { expect(err).to.not.exist; expect(accessToken).to.equal(users['test@example.com']); done(); }); }, 3000); }); - it('should emit access token update', function(done) { + it('should emit access token update', function (done) { let xoauth2 = new XOAuth2({ user: 'test@example.com', clientId: '{Client ID}', @@ -164,7 +164,7 @@ describe('XOAuth2 tests', function() { timeout: 3600 }); - xoauth2.once('token', function(tokenData) { + xoauth2.once('token', function (tokenData) { expect(tokenData.expires).to.be.gte(Date.now() + 3000 * 1000); expect(tokenData).to.deep.equal({ user: 'test@example.com', @@ -174,10 +174,10 @@ describe('XOAuth2 tests', function() { done(); }); - xoauth2.getToken(false, function() {}); + xoauth2.getToken(false, function () {}); }); - it('should sign payload', function() { + it('should sign payload', function () { let xoauth2 = new XOAuth2({ user: 'test@example.com', serviceClient: '{Client ID}',
.travis.yml+1 −0 modified@@ -4,6 +4,7 @@ node_js: - 10 - 12 - 14 + - 15 notifications: email: - andris@kreata.ee
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-48ww-j4fc-435pghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-7769ghsaADVISORY
- github.com/nodemailer/nodemailer/blob/33b62e2ea6bc9215c99a9bb4bfba94e2fb27ebd0/lib/sendmail-transport/index.jsghsaWEB
- github.com/nodemailer/nodemailer/blob/33b62e2ea6bc9215c99a9bb4bfba94e2fb27ebd0/lib/sendmail-transport/index.js%23L75ghsax_refsource_MISCWEB
- github.com/nodemailer/nodemailer/commit/ba31c64c910d884579875c52d57ac45acc47aa54ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1039742ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JS-NODEMAILER-1038834ghsax_refsource_MISCWEB
- www.npmjs.com/package/nodemailerghsaWEB
News mentions
0No linked articles in our index yet.