CVE-2020-7769 (JavaScript, published 2020-11-12T09:15Z)
Description: value: This affects the package nodemailer before 6.4.16. Use of crafted recipient email addresses may result in arbitrary command flag injection in sendmail transport for sending mails.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-88 \u2014 Improper Neutralization of Argument Delimiters in a Command ('Argument Injection')
The product constructs a string for a command to be executed by a separate component
in another control sphere, but it does not properly delimit the
intended arguments, options, or switches within that command string.
Repository: https://github.com/nodemailer/nodemailer
Files changed:
.travis.yml
Gruntfile.js
lib/dkim/message-parser.js
lib/fetch/cookies.js
lib/fetch/index.js
lib/mailer/mail-message.js
lib/mime-funcs/mime-types.js
lib/nodemailer.js
lib/sendmail-transport/index.js
lib/shared/index.js
lib/smtp-connection/http-proxy-client.js
lib/smtp-connection/index.js
lib/well-known/index.js
lib/well-known/services.json
lib/xoauth2/index.js
package.json
test/base64/base64-test.js
test/dkim/dkim-test.js
test/dkim/message-parser-test.js
test/dkim/relaxed-body-test.js
test/dkim/sign-test.js
test/ethereal-test.js
test/fetch/cookies-test.js
test/fetch/fetch-test.js
test/json-transport/json-transport-test.js
test/qp/qp-test.js
test/sendmail/le-unix.test.js
test/sendmail/le-windows-test.js
test/sendmail/sendmail-test.js
test/ses-transport/ses-transport-test.js
test/shared/shared-test.js
test/smtp-connection/http-proxy-client-test.js
test/smtp-connection/smtp-connection-test.js
test/smtp-connection/xoauth2-mock-server.js
test/smtp-pool/smtp-pool-test.js
test/smtp-transport/smtp-tranport-test.js
test/stream-transport/stream-transport-test.js
test/well-known/well-known-test.js
test/xoauth2/server.js
test/xoauth2/xoauth2-test.js
Commit message: v6.4.16


Vulnerable code:
module.exports = function(grunt) {
                key: line
                    .substr(0, line.indexOf(':'))
                    .trim()
                    .toLowerCase(),
                let key = valueParts
                    .shift()
                    .trim()
                    .toLowerCase();
module.exports = function(url, options) {
    let method =
        (options.method || '')
            .toString()
            .trim()
            .toUpperCase() || 'GET';
        method =
            (options.method || '')
                .toString()
                .trim()
                .toUpperCase() || 'POST';
                    attachment.filename =
                        (attachment.path || attachment.href || '')
                            .split('/')
                            .pop()
                            .split('?')
                            .shift() || 'attachment-' + (i + 1);
        let extension = (parsed.ext.substr(1) || parsed.name || '')
            .split('?')
            .shift()
            .trim()
            .toLowerCase();
        let parts = (mimeType || '')
            .toLowerCase()
            .trim()
            .split('/');
const ETHEREAL_CACHE = ['true', 'yes', 'y', '1'].includes(
    (process.env.ETHEREAL_CACHE || 'yes')
        .toString()
        .trim()
        .toLowerCase()
);
module.exports.createTransport = function(transporter, defaults) {
module.exports.createTestAccount = function(apiUrl, callback) {
module.exports.getTestMessageUrl = function(info) {
    function() {
module.exports.assign = function(/* target, ... sources */) {
            console.log(
                '[%s] %s %s',
                new Date()
                    .toISOString()
                    .substr(0, 19)
                    .replace(/T/, ' '),
                levelNames.get(level),
                prefix + line
            );
    let tempSocketErr = function(err) {
        this.id = crypto
            .randomBytes(8)
            .toString('base64')
            .replace(/\W/g, '');
            let mapKey = (key || '')
                .toString()
                .trim()
                .toUpperCase();
        this._authMethod =
            (this._auth.method || '')
                .toString()
                .trim()
                .toUpperCase() || false;
        let callback = function() {
module.exports = function(key) {
    
        "host": "smtp.ethereal.email",   
                if(data.error_description) {
                  errorMessage += ': ' + data.error_description;
                if(data.error_uri) {
                  errorMessage += ' (' + data.error_uri + ')';
    "version": "6.4.15",
describe('Base64 Tests', function() {
    describe('#encode', function() {
        it('shoud encode UTF-8 string to base64', function() {
            encodeFixtures.forEach(function(test) {
        it('shoud encode Buffer to base64', function() {
    describe('#wrap', function() {
        it('should wrap long base64 encoded lines', function() {
            wrapFixtures.forEach(function(test) {
    describe('base64 Streams', function() {
        it('should transform incoming bytes to base64', function(done) {
            encoder.on('data', function(chunk) {
            encoder.on('end', function(chunk) {
            let sendNextByte = function() {
        it('should transform incoming bytes to base64 and back', function(done) {
            file.on('data', function(chunk) {
            file.on('end', function() {
            decoder.on('data', function(chunk) {
            decoder.on('end', function() {
describe('DKIM Tests', function() {
    it('should sign message', function(done) {
    it('should sign large message using cache dir', function(done) {
    it('should sign large message without cache dir', function(done) {
    it('should emit cache error', function(done) {
    it('should sign large message as Buffer', function(done) {
    it('should sign large message as String', function(done) {
describe('DKIM MessageParser Tests', function() {
    it('should extract header and body', function(done) {
describe('DKIM RelaxedBody Tests', function() {
    it('Should calculate body hash byte by byte', function(done) {
    it('Should calculate body hash all at once', function(done) {
describe('DKIM Sign Tests', function() {
    it('should create relaxed headers', function() {
    it('should skip specific headers', function() {
    it('should sign headers', function() {
    it('should sign headers for unicode domain', function() {
describe('Ethereal Tests', function() {
    it('should create an account and send a message', function(done) {
    it('should cache a created test account', function(done) {
    it('should cache a created test account when using promises', function(done) {
describe('Cookie Tests', function() {
    beforeEach(function() {
    describe('#getPath', function() {
        it('should return root path', function() {
        it('should return without file', function() {
    describe('#isExpired', function() {
        it('should match expired cookie', function() {
    describe('#compare', function() {
        it('should match similar cookies', function() {
    describe('#add', function() {
        it('should append new cookie', function() {
        it('should update existing cookie', function() {
    describe('#match', function() {
        it('should check if a cookie matches particular domain and path', function() {
        it('should check if a cookie matches particular domain and path', function() {
        it('should check if a cookie is secure', function() {
    describe('#parse', function() {
        it('should parse Set-Cookie value', function() {
        it('should ignore invalid expire header', function() {
    describe('Listing', function() {
        beforeEach(function() {
        describe('#list', function() {
            it('should return matching cookies for an URL', function() {
        describe('#get', function() {
            it('should return matching cookies for an URL', function() {
    describe('#set', function() {
        it('should set cookie', function() {
                biskviit.cookies.map(function(cookie) {
describe('Fetch Tests', function() {
    beforeEach(function(done) {
        httpServer = http.createServer(function(req, res) {
                    req.on('readable', function() {
                    req.on('end', function() {
        httpsServer = https.createServer(httpsOptions, function(req, res) {
        httpServer.listen(HTTP_PORT, function() {
    afterEach(function(done) {
        httpServer.close(function() {
    it('should fetch HTTP data', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
    it('should fetch HTTPS data', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
    it('should fetch HTTP data with redirects', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
    it('should return error for too many redirects', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {});
    it('should fetch HTTP data with custom redirect limit', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
    it('should return error for custom redirect limit', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {});
    it('should return disable redirects', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {});
    it('should unzip compressed HTTP data', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
    it('should return error for unresolved host', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {});
    it('should return error for invalid status', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {});
    it('should allow invalid status', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {
    it('should return error for invalid url', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {});
    it('should return timeout error', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {});
    it('should handle basic HTTP auth', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
        it('should return error for invalid protocol', function(done) {
            req.on('data', function(chunk) {
            req.on('error', function(err) {
            req.on('end', function() {});
    it('should set cookie value', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
    it('should set user agent', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
    it('should post data', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
    it('should post stream data', function(done) {
        req.on('data', function(chunk) {
        req.on('end', function() {
        let writeNext = function() {
    it('should return error for invalid cert', function(done) {
        req.on('data', function(chunk) {
        req.on('error', function(err) {
        req.on('end', function() {});
describe('JSON Transport Tests', function() {
    it('should return an JSON string', function(done) {
    it('should return an JSON string for calendar event', function(done) {
describe('Quoted-Printable Tests', function() {
    describe('#encode', function() {
        it('shoud encode UTF-8 string to QP', function() {
            encodeFixtures.forEach(function(test) {
        it('shoud encode Buffer to QP', function() {
    describe('#wrap', function() {
        it('should wrap long QP encoded lines', function() {
            wrapFixtures.forEach(function(test) {
        it('should wrap line ending with <CR>', function() {
    describe('QP Streams', function() {
        it('should transform incoming bytes to QP', function(done) {
            encoder.on('data', function(chunk) {
            encoder.on('end', function(chunk) {
            let sendNextByte = function() {
        it('should transform incoming bytes to QP and back', function(done) {
            file.on('data', function(chunk) {
            file.on('end', function() {
            decoder.on('data', function(chunk) {
            decoder.on('end', function() {
describe('Sendmail Unix Newlines', function() {
    it('should rewrite all linebreaks (byte by byte)', function(done) {
    it('should rewrite all linebreaks (all at once)', function(done) {
describe('Sendmail Windows Newlines', function() {
    it('should rewrite all linebreaks (byte by byte)', function(done) {
    it('should rewrite all linebreaks (all at once)', function(done) {
describe('Sendmail Transport Tests', function() {
    it('Should expose version number', function() {
    it('Should send message', function(done) {
        stubbedSpawn.stdin.on('data', function(chunk) {
        stubbedSpawn.stdin.on('end', function() {
            function(err, data) {
    it('Should return an error', function(done) {
        stubbedSpawn.stdin.on('end', function() {
            function(err, data) {
describe('SES Transport Tests', function() {
    it('should return MessageId', function(done) {
    it('should sign message with DKIM', function(done) {
    it('should limit parallel connections', function(done) {
    it('should rate limit messages', function(done) {
    it('should rate limit long messages', function(done) {
    it('should rate limit messages and connections', function(done) {
    it('detect sending slots on idle events', function(done) {
describe('Shared Funcs Tests', function() {
    describe('Logger tests', function() {
        it('Should create a logger', function() {
    describe('Connection url parser tests', function() {
        it('Should parse connection url', function() {
        it('should not choke on special symbols in auth', function() {
    describe('Resolver tests', function() {
        beforeEach(function(done) {
            server = http.createServer(function(req, res) {
        afterEach(function(done) {
        it('should set text from html string', function(done) {
            shared.resolveContent(mail.data, 'html', function(err, value) {
        it('should set text from html buffer', function(done) {
            shared.resolveContent(mail.data, 'html', function(err, value) {
        it('should set text from a html file', function(done) {
            shared.resolveContent(mail.data, 'html', function(err, value) {
        it('should set text from an html url', function(done) {
            shared.resolveContent(mail.data, 'html', function(err, value) {
        it('should set text from redirecting url', function(done) {
            shared.resolveContent(mail.data, 'html', function(err, value) {
        it('should set text from gzipped url', function(done) {
            shared.resolveContent(mail.data, 'html', function(err, value) {
        it('should set text from a html stream', function(done) {
            shared.resolveContent(mail.data, 'html', function(err, value) {
        it('should return an error', function(done) {
            shared.resolveContent(mail.data, 'html', function(err) {
        it('should return encoded string as buffer', function(done) {
            shared.resolveContent(mail.data, 'html', function(err, value) {
        describe('data uri tests', function() {
            it('should resolve with mime type and base64', function(done) {
                shared.resolveContent(mail.data, 'attachment', function(err, value) {
            it('should resolve with mime type and plaintext', function(done) {
                shared.resolveContent(mail.data, 'attachment', function(err, value) {
            it('should resolve with plaintext', function(done) {
                shared.resolveContent(mail.data, 'attachment', function(err, value) {
            it('should resolve with mime type, charset and base64', function(done) {
                shared.resolveContent(mail.data, 'attachment', function(err, value) {
    describe('#assign tests', function() {
        it('should assign multiple objects to target', function() {
    describe('#encodeXText tests', function() {
        it('should not encode atom', function() {
        it('should not encode email', function() {
        it('should encode space', function() {
        it('should encode unicode', function() {
        it('should encode low codes', function() {
describe('HTTP Proxy Client Tests', function() {
    it('should connect to a socket through proxy', function(done) {
    it('should connect to a socket through proxy with auth', function(done) {
    it('should should fail auth', function(done) {
describe('SMTP-Connection Tests', function() {
    describe('Version test', function() {
        it('Should expose version number', function() {
    describe('Connection tests', function() {
        beforeEach(function(done) {
                onAuth: function(auth, session, callback) {
                onData: function(stream, session, callback) {
                    stream.on('data', function() {});
                onData: function(stream, session, callback) {
                    stream.on('data', function(chunk) {
                    stream.on('end', function() {
            invalidServer = net.createServer(function() {});
                onAuth: function(auth, session, callback) {
                onData: function(stream, session, callback) {
                    stream.on('data', function() {});
            server.listen(PORT_NUMBER, function() {
                invalidServer.listen(PORT_NUMBER + 1, function() {
                    secureServer.listen(PORT_NUMBER + 2, function() {
                        insecureServer.listen(PORT_NUMBER + 3, function() {
        afterEach(function(done) {
            server.close(function() {
                invalidServer.close(function() {
                    secureServer.close(function() {
                        insecureServer.close(function() {
        it('should connect to unsecure server', function(done) {
            client.connect(function() {
            client.on('error', function(err) {
        it('should connect to a server and upgrade with STARTTLS', function(done) {
            client.connect(function() {
            client.on('error', function(err) {
        it('should connect to a server and upgrade with forced STARTTLS', function(done) {
            client.connect(function() {
            client.on('error', function(err) {
        it('should connect to a server and try to upgrade STARTTLS', function(done) {
            client.connect(function() {
            client.on('error', function(err) {
        it('should try upgrade with STARTTLS where not advertised', function(done) {
            client.connect(function() {
            client.once('error', function(err) {
        it('should close connection after STARTTLS', function(done) {
            client.connect(function() {
                server.connections.forEach(function(conn) {
            client.on('error', function(err) {
        it('should connect to a secure server', function(done) {
            client.connect(function() {
            client.on('error', function(err) {
        it('should emit error for invalid port', function(done) {
            client.connect(function() {
            client.once('error', function(err) {
        it('should emit error for too large port', function(done) {
            client.connect(function() {
            client.once('error', function(err) {
        it('should emit inactivity timeout error', function(done) {
            client.connect(function() {
            client.once('error', function(err) {
        it('should connect through proxy', function(done) {
            let runTest = function(socket) {
                client.connect(function() {
                        function(err) {
                client.on('error', function(err) {
            proxyConnect(PROXY_PORT_NUMBER, '127.0.0.1', PORT_NUMBER, '127.0.0.1', function(err, socket) {
        it('should connect through proxy to secure server', function(done) {
            let runTest = function(socket) {
                client.connect(function() {
                        function(err) {
                client.on('error', function(err) {
            proxyConnect(PROXY_PORT_NUMBER, '127.0.0.1', PORT_NUMBER + 2, '127.0.0.1', function(err, socket) {
        it('should send to unsecure server', function(done) {
            client.on('error', function(err) {
            client.connect(function() {
                server.on('data', function(connection, chunk) {
                server.on('dataReady', function(connection, callback) {
                    expect(body.toString()).to.equal(
                        message
                            .toString()
                            .trim()
                            .replace(/\n/g, '\r\n')
                    );
                    function(err) {
    describe('Login tests', function() {
        beforeEach(function(done) {
                onData: function(stream, session, callback) {
                    stream.on('data', function(chunk) {
                    stream.on('end', function() {
                onAuth: function(auth, session, callback) {
                onMailFrom: function(address, session, callback) {
                onRcptTo: function(address, session, callback) {
                onData: function(stream, session, callback) {
                    stream.on('data', function() {});
                    stream.on('end', function() {
                        let response = session.envelope.rcptTo.map(function(rcpt, i) {
                onMailFrom: function(address, session, callback) {
                onRcptTo: function(address, session, callback) {
            server.listen(PORT_NUMBER, function() {
                lmtpServer.listen(LMTP_PORT_NUMBER, function() {
                    client.connect(function() {
        afterEach(function(done) {
            server.close(function() {
        it('should login', function(done) {
                function(err) {
        it('should return error for invalid login', function(done) {
                function(err) {
        it('should return error for missing credentials', function(done) {
                function(err) {
        it('should return error for incomplete credentials', function(done) {
                function(err) {
        describe('xoauth2 login', function() {
            beforeEach(function(done) {
                    onUpdate: function(username, accessToken) {
            afterEach(function(done) {
            it('should login with xoauth2 string', function(done) {
                    function(err) {
            it('should return error for invalid xoauth2 string token', function(done) {
                    function(err) {
            it('should login with xoauth2 object', function(done) {
                    function(err) {
            it('should fail with xoauth2 object', function(done) {
                    function(err) {
            it('should fail with invalid xoauth2 response', function(done) {
                    function(err) {
        describe('custom login', function() {
            beforeEach(function(done) {
            afterEach(function(done) {
            it('should login', function(done) {
                    function(err) {
        describe('Send without PIPELINING', function() {
            beforeEach(function(done) {
                client.on('end', function() {
                    client.connect(function() {
                            function(err) {
            it('should send only to valid recipients without PIPELINING', function(done) {
                    function(err, info) {
        describe('Send messages', function() {
            beforeEach(function(done) {
                    function(err) {
            it('should send message', function(done) {
                    function(err, info) {
            it('should send multiple messages', function(done) {
                    function(err, info) {
                        client.reset(function(err) {
                                function(err, info) {
            it('should send only to valid recipients', function(done) {
                    function(err, info) {
            it('should reject all recipients', function(done) {
                    function(err, info) {
            it('should reject too large SIZE arguments', function(done) {
                    function(err, info) {
            it('should reject too large message', function(done) {
                    function(err, info) {
            it('should declare SIZE', function(done) {
                    function(err, info) {
            it('lmtp should send only to valid recipients', function(done) {
                    function(err, info) {
            it('should send using SMTPUTF8', function(done) {
                    function(err, info) {
            it('should send using 8BITMIME', function(done) {
                    function(err, info) {
            it('should receive error for 8-bit content without 8BITMIME declaration', function(done) {
                    function(err) {
            it('should return error for invalidly formatted recipients', function(done) {
                    function(err) {
            it('should return error for no valid recipients', function(done) {
                    function(err) {
            it('should return error for invalid sender', function(done) {
                    function(err) {
            it('should send message string', function(done) {
                server.on('data', function(connection, chunk) {
                server.on('dataReady', function(connection, callback) {
                    function(err) {
            it('should send message buffer', function(done) {
                server.on('data', function(connection, chunk) {
                server.on('dataReady', function(connection, callback) {
                    expect(body.toString()).to.equal(
                        message
                            .toString()
                            .trim()
                            .replace(/\n/g, '\r\n')
                    );
                    function(err) {
            it('should send message stream', function(done) {
                server.on('data', function(connection, chunk) {
                server.on('dataReady', function(connection, callback) {
                    expect(body.toString()).to.equal(
                        message
                            .toString()
                            .trim()
                            .replace(/\n/g, '\r\n')
                    );
                    function(err) {
    let socket = net.connect(port, host, function() {
        let onSocketData = function(chunk) {
    socket.on('error', function(err) {
module.exports = function(options) {
OAuthServer.prototype.addUser = function(username, refreshToken) {
OAuthServer.prototype.generateAccessToken = function(refreshToken) {
OAuthServer.prototype.validateAccessToken = function(username, accessToken) {
OAuthServer.prototype.start = function(callback) {
OAuthServer.prototype.stop = function(callback) {
describe('SMTP Pool Tests', function() {
    beforeEach(function(done) {
                stream.on('data', function() {});
    afterEach(function(done) {
    it('Should expose version number', function() {
    it('Should detect wellknown data', function() {
    it('should send mail', function(done) {
        server.onData = function(stream, session, callback) {
            stream.on('data', function(chunk) {
            stream.on('end', function() {
            function(err) {
    it('should send multiple mails', function(done) {
        server.onData = function(stream, session, callback) {
            stream.on('data', function(chunk) {
            stream.on('end', function() {
                function(err) {
        let cb = function() {
                pool._connections.forEach(function(conn) {
    it('should tolerate connection errors', function(done) {
        server.onData = function(stream, session, callback) {
            stream.on('data', function(chunk) {
            stream.on('end', function() {
                function(err) {
        let cb = function() {
    it('should tolerate idle connections and re-assign messages to other connections', function(done) {
        server.onData = function(stream, session, callback) {
            stream.on('data', function() {
                    server.connections.forEach(function(connection) {
            stream.on('end', function() {
                function(err) {
        let cb = function() {
    it('should call back with connection errors to senders having messages in flight', function(done) {
            function(err) {
            function(err) {
    it('should not send more then allowed for one connection', function(done) {
        server.onData = function(stream, session, callback) {
            stream.on('data', function(chunk) {
            stream.on('end', function() {
                function(err) {
        let cb = function() {
    it('should send multiple mails with rate limit', function(done) {
        server.onData = function(stream, session, callback) {
            stream.on('data', function(chunk) {
            stream.on('end', function() {
                function(err) {
        let cb = function() {
        let send = function() {
    it('should return pending messages once closed', function(done) {
        server.onData = function(stream, session, callback) {
            stream.on('data', function(chunk) {
            stream.on('end', function() {
                function(err) {
        let cb = function() {
    it('should emit idle for free slots in the pool', function(done) {
        server.onData = function(stream, session, callback) {
            stream.on('data', function(chunk) {
            stream.on('end', function() {
        let cb = function() {
        pool.on('idle', function() {
            setTimeout(function() {
                    setImmediate(function() {
    it('Should login and send mail using proxied socket', function(done) {
                let errHandler = function(err) {
                socket.on('connect', function() {
        server.on('data', function(connection, chunk) {
        server.on('dataReady', function(connection, callback) {
            function(err) {
    it('Should verify connection with success', function(done) {
        client.verify(function(err, success) {
    it('Should not verify connection', function(done) {
        client.verify(function(err) {
describe('SMTP Transport Tests', function() {
    describe('Anonymous sender tests', function() {
        beforeEach(function(done) {
                    stream.on('data', function() {});
        afterEach(function(done) {
        it('Should expose version number', function() {
        it('Should detect wellknown data', function() {
        it('Should fail envelope', function(done) {
                function(err) {
        it('Should not fail auth', function(done) {
                function(err) {
        it('Should fail auth if forceAuth=true', function(done) {
                function(err) {
        it('Should send mail', function(done) {
            server.on('data', function(connection, chunk) {
            server.on('dataReady', function(connection, callback) {
                function(err) {
        it('Should recover unexpeced close during transmission', function(done) {
            server.on('data', function(connection, chunk) {
            server.on('dataReady', function(connection, callback) {
                function(err) {
    describe('Authenticated sender tests', function() {
        beforeEach(function(done) {
                    stream.on('data', function() {});
        afterEach(function(done) {
        it('Should login and send mail', function(done) {
            server.on('data', function(connection, chunk) {
            server.on('dataReady', function(connection, callback) {
                function(err) {
        it('Should verify connection with success', function(done) {
            client.verify(function(err, success) {
        it('Should not verify connection', function(done) {
            client.verify(function(err) {
        it('Should login and send mail using proxied socket', function(done) {
                    let errHandler = function(err) {
                    socket.on('connect', function() {
            server.on('data', function(connection, chunk) {
            server.on('dataReady', function(connection, callback) {
                function(err) {
describe('Stream Transport Tests', function() {
    it('Should expose version number', function() {
    describe('Send as stream', function() {
        it('Should send mail using unix newlines', function(done) {
                function(err, info) {
                    info.message.on('data', function(chunk) {
                    info.message.on('end', function() {
        it('Should send mail using windows newlines', function(done) {
                function(err, info) {
                    info.message.on('data', function(chunk) {
                    info.message.on('end', function() {
    describe('Send as buffer', function() {
        it('Should send mail using unix newlines', function(done) {
                function(err, info) {
        it('Should send mail using windows newlines', function(done) {
                function(err, info) {
describe('Well-Known Services Tests', function() {
    describe('#wellKnown', function() {
        it('Should find by key', function() {
        it('Should find by alias', function() {
        it('Should find by domain', function() {
        it('Should find no match', function() {
module.exports = function(options) {
OAuthServer.prototype.addUser = function(username, refreshToken) {
OAuthServer.prototype.generateAccessToken = function(refreshToken) {
OAuthServer.prototype.validateAccessToken = function(username, accessToken) {
OAuthServer.prototype.start = function(callback) {
OAuthServer.prototype.stop = function(callback) {
describe('XOAuth2 tests', function() {
    beforeEach(function(done) {
            onUpdate: function(username, accessToken) {
    afterEach(function(done) {
    it('should get an existing access token', function(done) {
        xoauth2.getToken(false, function(err, accessToken) {
    it('should convert access token to XOAuth2 token', function() {
    it('should get an existing access token, no timeout', function(done) {
        xoauth2.getToken(false, function(err, accessToken) {
    it('should generate a fresh access token', function(done) {
        xoauth2.getToken(false, function(err, accessToken) {
    it('should generate a fresh access token with custom method', function(done) {
        xoauth2.getToken(false, function(err, accessToken) {
    it('should fail generating a fresh access token with custom method', function(done) {
        xoauth2.getToken(false, function(err, accessToken) {
    it('should generate a fresh access token after timeout', function(done) {
        setTimeout(function() {
            xoauth2.getToken(false, function(err, accessToken) {
    it('should emit access token update', function(done) {
        xoauth2.once('token', function(tokenData) {
        xoauth2.getToken(false, function() {});
    it('should sign payload', function() {

Fixed code:
    - 15
module.exports = function (grunt) {
                key: line.substr(0, line.indexOf(':')).trim().toLowerCase(),
                let key = valueParts.shift().trim().toLowerCase();
module.exports = function (url, options) {
    let method = (options.method || '').toString().trim().toUpperCase() || 'GET';
        method = (options.method || '').toString().trim().toUpperCase() || 'POST';
                    attachment.filename = (attachment.path || attachment.href || '').split('/').pop().split('?').shift() || 'attachment-' + (i + 1);
        let extension = (parsed.ext.substr(1) || parsed.name || '').split('?').shift().trim().toLowerCase();
        let parts = (mimeType || '').toLowerCase().trim().split('/');
const ETHEREAL_CACHE = ['true', 'yes', 'y', '1'].includes((process.env.ETHEREAL_CACHE || 'yes').toString().trim().toLowerCase());
module.exports.createTransport = function (transporter, defaults) {
module.exports.createTestAccount = function (apiUrl, callback) {
module.exports.getTestMessageUrl = function (info) {
        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.'));
        }

    function () {
module.exports.assign = function (/* target, ... sources */) {
            console.log('[%s] %s %s', new Date().toISOString().substr(0, 19).replace(/T/, ' '), levelNames.get(level), prefix + line);
    let tempSocketErr = function (err) {
        this.id = crypto.randomBytes(8).toString('base64').replace(/\W/g, '');
            let mapKey = (key || '').toString().trim().toUpperCase();
        this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false;
        let callback = function () {
module.exports = function (key) {

        "host": "smtp.ethereal.email",
                if (data.error_description) {
                    errorMessage += ': ' + data.error_description;
                if (data.error_uri) {
                    errorMessage += ' (' + data.error_uri + ')';
    "version": "6.4.16",
describe('Base64 Tests', function () {
    describe('#encode', function () {
        it('shoud encode UTF-8 string to base64', function () {
            encodeFixtures.forEach(function (test) {
        it('shoud encode Buffer to base64', function () {
    describe('#wrap', function () {
        it('should wrap long base64 encoded lines', function () {
            wrapFixtures.forEach(function (test) {
    describe('base64 Streams', function () {
        it('should transform incoming bytes to base64', function (done) {
            encoder.on('data', function (chunk) {
            encoder.on('end', function (chunk) {
            let sendNextByte = function () {
        it('should transform incoming bytes to base64 and back', function (done) {
            file.on('data', function (chunk) {
            file.on('end', function () {
            decoder.on('data', function (chunk) {
            decoder.on('end', function () {
describe('DKIM Tests', function () {
    it('should sign message', function (done) {
    it('should sign large message using cache dir', function (done) {
    it('should sign large message without cache dir', function (done) {
    it('should emit cache error', function (done) {
    it('should sign large message as Buffer', function (done) {
    it('should sign large message as String', function (done) {
describe('DKIM MessageParser Tests', function () {
    it('should extract header and body', function (done) {
describe('DKIM RelaxedBody Tests', function () {
    it('Should calculate body hash byte by byte', function (done) {
    it('Should calculate body hash all at once', function (done) {
describe('DKIM Sign Tests', function () {
    it('should create relaxed headers', function () {
    it('should skip specific headers', function () {
    it('should sign headers', function () {
    it('should sign headers for unicode domain', function () {
describe('Ethereal Tests', function () {
    it('should create an account and send a message', function (done) {
    it('should cache a created test account', function (done) {
    it('should cache a created test account when using promises', function (done) {
describe('Cookie Tests', function () {
    beforeEach(function () {
    describe('#getPath', function () {
        it('should return root path', function () {
        it('should return without file', function () {
    describe('#isExpired', function () {
        it('should match expired cookie', function () {
    describe('#compare', function () {
        it('should match similar cookies', function () {
    describe('#add', function () {
        it('should append new cookie', function () {
        it('should update existing cookie', function () {
    describe('#match', function () {
        it('should check if a cookie matches particular domain and path', function () {
        it('should check if a cookie matches particular domain and path', function () {
        it('should check if a cookie is secure', function () {
    describe('#parse', function () {
        it('should parse Set-Cookie value', function () {
        it('should ignore invalid expire header', function () {
    describe('Listing', function () {
        beforeEach(function () {
        describe('#list', function () {
            it('should return matching cookies for an URL', function () {
        describe('#get', function () {
            it('should return matching cookies for an URL', function () {
    describe('#set', function () {
        it('should set cookie', function () {
                biskviit.cookies.map(function (cookie) {
describe('Fetch Tests', function () {
    beforeEach(function (done) {
        httpServer = http.createServer(function (req, res) {
                    req.on('readable', function () {
                    req.on('end', function () {
        httpsServer = https.createServer(httpsOptions, function (req, res) {
        httpServer.listen(HTTP_PORT, function () {
    afterEach(function (done) {
        httpServer.close(function () {
    it('should fetch HTTP data', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
    it('should fetch HTTPS data', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
    it('should fetch HTTP data with redirects', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
    it('should return error for too many redirects', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {});
    it('should fetch HTTP data with custom redirect limit', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
    it('should return error for custom redirect limit', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {});
    it('should return disable redirects', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {});
    it('should unzip compressed HTTP data', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
    it('should return error for unresolved host', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {});
    it('should return error for invalid status', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {});
    it('should allow invalid status', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {
    it('should return error for invalid url', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {});
    it('should return timeout error', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {});
    it('should handle basic HTTP auth', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
        it('should return error for invalid protocol', function (done) {
            req.on('data', function (chunk) {
            req.on('error', function (err) {
            req.on('end', function () {});
    it('should set cookie value', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
    it('should set user agent', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
    it('should post data', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
    it('should post stream data', function (done) {
        req.on('data', function (chunk) {
        req.on('end', function () {
        let writeNext = function () {
    it('should return error for invalid cert', function (done) {
        req.on('data', function (chunk) {
        req.on('error', function (err) {
        req.on('end', function () {});
describe('JSON Transport Tests', function () {
    it('should return an JSON string', function (done) {
    it('should return an JSON string for calendar event', function (done) {
describe('Quoted-Printable Tests', function () {
    describe('#encode', function () {
        it('shoud encode UTF-8 string to QP', function () {
            encodeFixtures.forEach(function (test) {
        it('shoud encode Buffer to QP', function () {
    describe('#wrap', function () {
        it('should wrap long QP encoded lines', function () {
            wrapFixtures.forEach(function (test) {
        it('should wrap line ending with <CR>', function () {
    describe('QP Streams', function () {
        it('should transform incoming bytes to QP', function (done) {
            encoder.on('data', function (chunk) {
            encoder.on('end', function (chunk) {
            let sendNextByte = function () {
        it('should transform incoming bytes to QP and back', function (done) {
            file.on('data', function (chunk) {
            file.on('end', function () {
            decoder.on('data', function (chunk) {
            decoder.on('end', function () {
describe('Sendmail Unix Newlines', function () {
    it('should rewrite all linebreaks (byte by byte)', function (done) {
    it('should rewrite all linebreaks (all at once)', function (done) {
describe('Sendmail Windows Newlines', function () {
    it('should rewrite all linebreaks (byte by byte)', function (done) {
    it('should rewrite all linebreaks (all at once)', function (done) {
describe('Sendmail Transport Tests', function () {
    it('Should expose version number', function () {
    it('Should send message', function (done) {
        stubbedSpawn.stdin.on('data', function (chunk) {
        stubbedSpawn.stdin.on('end', function () {
            function (err, data) {
    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) {
        stubbedSpawn.stdin.on('end', function () {
            function (err, data) {
describe('SES Transport Tests', function () {
    it('should return MessageId', function (done) {
    it('should sign message with DKIM', function (done) {
    it('should limit parallel connections', function (done) {
    it('should rate limit messages', function (done) {
    it('should rate limit long messages', function (done) {
    it('should rate limit messages and connections', function (done) {
    it('detect sending slots on idle events', function (done) {
describe('Shared Funcs Tests', function () {
    describe('Logger tests', function () {
        it('Should create a logger', function () {
    describe('Connection url parser tests', function () {
        it('Should parse connection url', function () {
        it('should not choke on special symbols in auth', function () {
    describe('Resolver tests', function () {
        beforeEach(function (done) {
            server = http.createServer(function (req, res) {
        afterEach(function (done) {
        it('should set text from html string', function (done) {
            shared.resolveContent(mail.data, 'html', function (err, value) {
        it('should set text from html buffer', function (done) {
            shared.resolveContent(mail.data, 'html', function (err, value) {
        it('should set text from a html file', function (done) {
            shared.resolveContent(mail.data, 'html', function (err, value) {
        it('should set text from an html url', function (done) {
            shared.resolveContent(mail.data, 'html', function (err, value) {
        it('should set text from redirecting url', function (done) {
            shared.resolveContent(mail.data, 'html', function (err, value) {
        it('should set text from gzipped url', function (done) {
            shared.resolveContent(mail.data, 'html', function (err, value) {
        it('should set text from a html stream', function (done) {
            shared.resolveContent(mail.data, 'html', function (err, value) {
        it('should return an error', function (done) {
            shared.resolveContent(mail.data, 'html', function (err) {
        it('should return encoded string as buffer', function (done) {
            shared.resolveContent(mail.data, 'html', function (err, value) {
        describe('data uri tests', function () {
            it('should resolve with mime type and base64', function (done) {
                shared.resolveContent(mail.data, 'attachment', function (err, value) {
            it('should resolve with mime type and plaintext', function (done) {
                shared.resolveContent(mail.data, 'attachment', function (err, value) {
            it('should resolve with plaintext', function (done) {
                shared.resolveContent(mail.data, 'attachment', function (err, value) {
            it('should resolve with mime type, charset and base64', function (done) {
                shared.resolveContent(mail.data, 'attachment', function (err, value) {
    describe('#assign tests', function () {
        it('should assign multiple objects to target', function () {
    describe('#encodeXText tests', function () {
        it('should not encode atom', function () {
        it('should not encode email', function () {
        it('should encode space', function () {
        it('should encode unicode', function () {
        it('should encode low codes', function () {
describe('HTTP Proxy Client Tests', function () {
    it('should connect to a socket through proxy', function (done) {
    it('should connect to a socket through proxy with auth', function (done) {
    it('should should fail auth', function (done) {
describe('SMTP-Connection Tests', function () {
    describe('Version test', function () {
        it('Should expose version number', function () {
    describe('Connection tests', function () {
        beforeEach(function (done) {
                onAuth: function (auth, session, callback) {
                onData: function (stream, session, callback) {
                    stream.on('data', function () {});
                onData: function (stream, session, callback) {
                    stream.on('data', function (chunk) {
                    stream.on('end', function () {
            invalidServer = net.createServer(function () {});
                onAuth: function (auth, session, callback) {
                onData: function (stream, session, callback) {
                    stream.on('data', function () {});
            server.listen(PORT_NUMBER, function () {
                invalidServer.listen(PORT_NUMBER + 1, function () {
                    secureServer.listen(PORT_NUMBER + 2, function () {
                        insecureServer.listen(PORT_NUMBER + 3, function () {
        afterEach(function (done) {
            server.close(function () {
                invalidServer.close(function () {
                    secureServer.close(function () {
                        insecureServer.close(function () {
        it('should connect to unsecure server', function (done) {
            client.connect(function () {
            client.on('error', function (err) {
        it('should connect to a server and upgrade with STARTTLS', function (done) {
            client.connect(function () {
            client.on('error', function (err) {
        it('should connect to a server and upgrade with forced STARTTLS', function (done) {
            client.connect(function () {
            client.on('error', function (err) {
        it('should connect to a server and try to upgrade STARTTLS', function (done) {
            client.connect(function () {
            client.on('error', function (err) {
        it('should try upgrade with STARTTLS where not advertised', function (done) {
            client.connect(function () {
            client.once('error', function (err) {
        it('should close connection after STARTTLS', function (done) {
            client.connect(function () {
                server.connections.forEach(function (conn) {
            client.on('error', function (err) {
        it('should connect to a secure server', function (done) {
            client.connect(function () {
            client.on('error', function (err) {
        it('should emit error for invalid port', function (done) {
            client.connect(function () {
            client.once('error', function (err) {
        it('should emit error for too large port', function (done) {
            client.connect(function () {
            client.once('error', function (err) {
        it('should emit inactivity timeout error', function (done) {
            client.connect(function () {
            client.once('error', function (err) {
        it('should connect through proxy', function (done) {
            let runTest = function (socket) {
                client.connect(function () {
                        function (err) {
                client.on('error', function (err) {
            proxyConnect(PROXY_PORT_NUMBER, '127.0.0.1', PORT_NUMBER, '127.0.0.1', function (err, socket) {
        it('should connect through proxy to secure server', function (done) {
            let runTest = function (socket) {
                client.connect(function () {
                        function (err) {
                client.on('error', function (err) {
            proxyConnect(PROXY_PORT_NUMBER, '127.0.0.1', PORT_NUMBER + 2, '127.0.0.1', function (err, socket) {
        it('should send to unsecure server', function (done) {
            client.on('error', function (err) {
            client.connect(function () {
                server.on('data', function (connection, chunk) {
                server.on('dataReady', function (connection, callback) {
                    expect(body.toString()).to.equal(message.toString().trim().replace(/\n/g, '\r\n'));
                    function (err) {
    describe('Login tests', function () {
        beforeEach(function (done) {
                onData: function (stream, session, callback) {
                    stream.on('data', function (chunk) {
                    stream.on('end', function () {
                onAuth: function (auth, session, callback) {
                onMailFrom: function (address, session, callback) {
                onRcptTo: function (address, session, callback) {
                onData: function (stream, session, callback) {
                    stream.on('data', function () {});
                    stream.on('end', function () {
                        let response = session.envelope.rcptTo.map(function (rcpt, i) {
                onMailFrom: function (address, session, callback) {
                onRcptTo: function (address, session, callback) {
            server.listen(PORT_NUMBER, function () {
                lmtpServer.listen(LMTP_PORT_NUMBER, function () {
                    client.connect(function () {
        afterEach(function (done) {
            server.close(function () {
        it('should login', function (done) {
                function (err) {
        it('should return error for invalid login', function (done) {
                function (err) {
        it('should return error for missing credentials', function (done) {
                function (err) {
        it('should return error for incomplete credentials', function (done) {
                function (err) {
        describe('xoauth2 login', function () {
            beforeEach(function (done) {
                    onUpdate: function (username, accessToken) {
            afterEach(function (done) {
            it('should login with xoauth2 string', function (done) {
                    function (err) {
            it('should return error for invalid xoauth2 string token', function (done) {
                    function (err) {
            it('should login with xoauth2 object', function (done) {
                    function (err) {
            it('should fail with xoauth2 object', function (done) {
                    function (err) {
            it('should fail with invalid xoauth2 response', function (done) {
                    function (err) {
        describe('custom login', function () {
            beforeEach(function (done) {
            afterEach(function (done) {
            it('should login', function (done) {
                    function (err) {
        describe('Send without PIPELINING', function () {
            beforeEach(function (done) {
                client.on('end', function () {
                    client.connect(function () {
                            function (err) {
            it('should send only to valid recipients without PIPELINING', function (done) {
                    function (err, info) {
        describe('Send messages', function () {
            beforeEach(function (done) {
                    function (err) {
            it('should send message', function (done) {
                    function (err, info) {
            it('should send multiple messages', function (done) {
                    function (err, info) {
                        client.reset(function (err) {
                                function (err, info) {
            it('should send only to valid recipients', function (done) {
                    function (err, info) {
            it('should reject all recipients', function (done) {
                    function (err, info) {
            it('should reject too large SIZE arguments', function (done) {
                    function (err, info) {
            it('should reject too large message', function (done) {
                    function (err, info) {
            it('should declare SIZE', function (done) {
                    function (err, info) {
            it('lmtp should send only to valid recipients', function (done) {
                    function (err, info) {
            it('should send using SMTPUTF8', function (done) {
                    function (err, info) {
            it('should send using 8BITMIME', function (done) {
                    function (err, info) {
            it('should receive error for 8-bit content without 8BITMIME declaration', function (done) {
                    function (err) {
            it('should return error for invalidly formatted recipients', function (done) {
                    function (err) {
            it('should return error for no valid recipients', function (done) {
                    function (err) {
            it('should return error for invalid sender', function (done) {
                    function (err) {
            it('should send message string', function (done) {
                server.on('data', function (connection, chunk) {
                server.on('dataReady', function (connection, callback) {
                    function (err) {
            it('should send message buffer', function (done) {
                server.on('data', function (connection, chunk) {
                server.on('dataReady', function (connection, callback) {
                    expect(body.toString()).to.equal(message.toString().trim().replace(/\n/g, '\r\n'));
                    function (err) {
            it('should send message stream', function (done) {
                server.on('data', function (connection, chunk) {
                server.on('dataReady', function (connection, callback) {
                    expect(body.toString()).to.equal(message.toString().trim().replace(/\n/g, '\r\n'));
                    function (err) {
    let socket = net.connect(port, host, function () {
        let onSocketData = function (chunk) {
    socket.on('error', function (err) {
module.exports = function (options) {
OAuthServer.prototype.addUser = function (username, refreshToken) {
OAuthServer.prototype.generateAccessToken = function (refreshToken) {
OAuthServer.prototype.validateAccessToken = function (username, accessToken) {
OAuthServer.prototype.start = function (callback) {
OAuthServer.prototype.stop = function (callback) {
describe('SMTP Pool Tests', function () {
    beforeEach(function (done) {
                stream.on('data', function () {});
    afterEach(function (done) {
    it('Should expose version number', function () {
    it('Should detect wellknown data', function () {
    it('should send mail', function (done) {
        server.onData = function (stream, session, callback) {
            stream.on('data', function (chunk) {
            stream.on('end', function () {
            function (err) {
    it('should send multiple mails', function (done) {
        server.onData = function (stream, session, callback) {
            stream.on('data', function (chunk) {
            stream.on('end', function () {
                function (err) {
        let cb = function () {
                pool._connections.forEach(function (conn) {
    it('should tolerate connection errors', function (done) {
        server.onData = function (stream, session, callback) {
            stream.on('data', function (chunk) {
            stream.on('end', function () {
                function (err) {
        let cb = function () {
    it('should tolerate idle connections and re-assign messages to other connections', function (done) {
        server.onData = function (stream, session, callback) {
            stream.on('data', function () {
                    server.connections.forEach(function (connection) {
            stream.on('end', function () {
                function (err) {
        let cb = function () {
    it('should call back with connection errors to senders having messages in flight', function (done) {
            function (err) {
            function (err) {
    it('should not send more then allowed for one connection', function (done) {
        server.onData = function (stream, session, callback) {
            stream.on('data', function (chunk) {
            stream.on('end', function () {
                function (err) {
        let cb = function () {
    it('should send multiple mails with rate limit', function (done) {
        server.onData = function (stream, session, callback) {
            stream.on('data', function (chunk) {
            stream.on('end', function () {
                function (err) {
        let cb = function () {
        let send = function () {
    it('should return pending messages once closed', function (done) {
        server.onData = function (stream, session, callback) {
            stream.on('data', function (chunk) {
            stream.on('end', function () {
                function (err) {
        let cb = function () {
    it('should emit idle for free slots in the pool', function (done) {
        server.onData = function (stream, session, callback) {
            stream.on('data', function (chunk) {
            stream.on('end', function () {
        let cb = function () {
        pool.on('idle', function () {
            setTimeout(function () {
                    setImmediate(function () {
    it('Should login and send mail using proxied socket', function (done) {
                let errHandler = function (err) {
                socket.on('connect', function () {
        server.on('data', function (connection, chunk) {
        server.on('dataReady', function (connection, callback) {
            function (err) {
    it('Should verify connection with success', function (done) {
        client.verify(function (err, success) {
    it('Should not verify connection', function (done) {
        client.verify(function (err) {
describe('SMTP Transport Tests', function () {
    describe('Anonymous sender tests', function () {
        beforeEach(function (done) {
                    stream.on('data', function () {});
        afterEach(function (done) {
        it('Should expose version number', function () {
        it('Should detect wellknown data', function () {
        it('Should fail envelope', function (done) {
                function (err) {
        it('Should not fail auth', function (done) {
                function (err) {
        it('Should fail auth if forceAuth=true', function (done) {
                function (err) {
        it('Should send mail', function (done) {
            server.on('data', function (connection, chunk) {
            server.on('dataReady', function (connection, callback) {
                function (err) {
        it('Should recover unexpeced close during transmission', function (done) {
            server.on('data', function (connection, chunk) {
            server.on('dataReady', function (connection, callback) {
                function (err) {
    describe('Authenticated sender tests', function () {
        beforeEach(function (done) {
                    stream.on('data', function () {});
        afterEach(function (done) {
        it('Should login and send mail', function (done) {
            server.on('data', function (connection, chunk) {
            server.on('dataReady', function (connection, callback) {
                function (err) {
        it('Should verify connection with success', function (done) {
            client.verify(function (err, success) {
        it('Should not verify connection', function (done) {
            client.verify(function (err) {
        it('Should login and send mail using proxied socket', function (done) {
                    let errHandler = function (err) {
                    socket.on('connect', function () {
            server.on('data', function (connection, chunk) {
            server.on('dataReady', function (connection, callback) {
                function (err) {
describe('Stream Transport Tests', function () {
    it('Should expose version number', function () {
    describe('Send as stream', function () {
        it('Should send mail using unix newlines', function (done) {
                function (err, info) {
                    info.message.on('data', function (chunk) {
                    info.message.on('end', function () {
        it('Should send mail using windows newlines', function (done) {
                function (err, info) {
                    info.message.on('data', function (chunk) {
                    info.message.on('end', function () {
    describe('Send as buffer', function () {
        it('Should send mail using unix newlines', function (done) {
                function (err, info) {
        it('Should send mail using windows newlines', function (done) {
                function (err, info) {
describe('Well-Known Services Tests', function () {
    describe('#wellKnown', function () {
        it('Should find by key', function () {
        it('Should find by alias', function () {
        it('Should find by domain', function () {
        it('Should find no match', function () {
module.exports = function (options) {
OAuthServer.prototype.addUser = function (username, refreshToken) {
OAuthServer.prototype.generateAccessToken = function (refreshToken) {
OAuthServer.prototype.validateAccessToken = function (username, accessToken) {
OAuthServer.prototype.start = function (callback) {
OAuthServer.prototype.stop = function (callback) {
describe('XOAuth2 tests', function () {
    beforeEach(function (done) {
            onUpdate: function (username, accessToken) {
    afterEach(function (done) {
    it('should get an existing access token', function (done) {
        xoauth2.getToken(false, function (err, accessToken) {
    it('should convert access token to XOAuth2 token', function () {
    it('should get an existing access token, no timeout', function (done) {
        xoauth2.getToken(false, function (err, accessToken) {
    it('should generate a fresh access token', function (done) {
        xoauth2.getToken(false, function (err, accessToken) {
    it('should generate a fresh access token with custom method', function (done) {
        xoauth2.getToken(false, function (err, accessToken) {
    it('should fail generating a fresh access token with custom method', function (done) {
        xoauth2.getToken(false, function (err, accessToken) {
    it('should generate a fresh access token after timeout', function (done) {
        setTimeout(function () {
            xoauth2.getToken(false, function (err, accessToken) {
    it('should emit access token update', function (done) {
        xoauth2.once('token', function (tokenData) {
        xoauth2.getToken(false, function () {});
    it('should sign payload', function () {