Example #1
0
function startDNSQueries(params){
  let domain = params.email.split(/[@]/).splice(-1)[0].toLowerCase()

  logger.info("Resolving DNS... " + domain)
  dns.resolveMx(domain,(err,addresses) => {
    if (err || (typeof addresses === 'undefined')) {
      params.callback(err, { success: false, info: 'Domain not found', code: infoCodes.domainNotFound });
    }
    else if (addresses && addresses.length <= 0) {
      params.callback(null, { success: false, info: 'No MX Records', code: infoCodes.noMxRecords });
    }
    else{
      params.addresses = addresses

      // Find the lowest priority mail server
      let priority = 10000,
          lowestPriorityIndex = 0

      for (let i = 0 ; i < addresses.length ; i++) {
        if (addresses[i].priority < priority) {
            priority = addresses[i].priority
            lowestPriorityIndex = i
            logger.info('MX Records ' + JSON.stringify(addresses[i]))
        }
      }

      params.options.smtp = addresses[lowestPriorityIndex].exchange
      logger.info("Choosing " + params.options.smtp + " for connection")
      beginSMTPQueries(params)
    }


  })
}
Example #2
0
 dns.resolve4(params[0], function (err, addresses) {
     var message = 'A: ';
     message += err || JSON.stringify(addresses, null, 2).replace(/[\r\n]/g, '');
     dns.resolveMx(params[0], function (err, addresses) {
         message += '\nMX: ';
         message += err || JSON.stringify(addresses, null, 2).replace(/[\r\n]/g, '');
         dns.resolveTxt(params[0], function (err, addresses) {
             message += '\nTxt: ';
             message += err || JSON.stringify(addresses, null, 2).replace(/[\r\n]/g, '');
             dns.resolveSrv(params[0], function (err, addresses) {
                 message += '\nSrv: ';
                 message += err || JSON.stringify(addresses, null, 2).replace(/[\r\n]/g, '');
                 dns.resolveNs(params[0], function (err, addresses) {
                     message += '\nNS: ';
                     message += err || JSON.stringify(addresses, null, 2).replace(/[\r\n]/g, '');
                     dns.resolveCname(params[0], function (err, addresses) {
                         message += '\nCName: ';
                         message += err || JSON.stringify(addresses, null, 2).replace(/[\r\n]/g, '');
                         stanza.c('body').t(message);
                         client.send(stanza);
                     });
                 });
             });
         });
     });
 });
Example #3
0
 dns.resolveNs(domain, function (err, addresses) {
   //if (err) throw err;
   if (!err) {
     //console.log('NS: ' + (addresses));
     for (var x in addresses) { console.log(addresses[x]) }
   }
   dns.resolveMx(domain, function (err, addresses) {
     //if (err) throw err;
     if (!err) {
       addresses.forEach(function (a) {
         console.log(a);
       });
     }
     // adds.forEach(function (a) {
     //   dns.reverse(a, function (err, domains) {
     //     if (err) {
     //       console.log('reverse for ' + a + ' failed: ' + err.message);
     //     } else {
     //       console.log('reverse for ' + a + ': ' + domains);
     //       //JSON.stringify(domains));
     //     }
     //   });
     // });
   });
 });
Example #4
0
  /**
   * connect to domain by Mx record
   */
  function connectMx(domain, callback) {
    dns.resolveMx(domain, function(err, data) {
        if (err)
          return callback(err);

        data.sort(function(a, b) {return a.priority < b. priority});
        logger.debug('mx resolved: ', data);

        if (!data || data.length == 0)
          return callback(new Error('can not resolve Mx of <' + domain + '>'));

        function tryConnect(i) {

          if (i >= data.length) return callback(new Error('can not connect to any SMTP server'));

          var sock = tcp.createConnection(25, data[i].exchange);

          sock.on('error', function(err) {
              logger.error('Error on connectMx for: ', data[i], err);
              tryConnect(++i);
          });

          sock.on('connect', function() {
              logger.debug("MX connection created: ", data[i].exchange);
              sock.removeAllListeners('error');
              callback(null, sock);
          });

        };

        tryConnect(0);
    });
  }
Example #5
0
 prepareDns(DnsServer.testResolveMX(prio, name), function() {
   dns.resolveMx("vertx.io", function(err, records) {
     vassert.assertTrue("Unexpected error: " + err, err === null);
     vassert.assertTrue("Unexpected priority: " + records[0], prio == records[0].priority);
     vassert.assertTrue("Unexpected exchange: " + records[0], name === records[0].exchange);
     vassert.testComplete();
   });
 });
Example #6
0
 var validateViaDNS = function () {
     dnslib.resolveMx(domain, (function(err, addresses){
         if(err || !addresses || !addresses.length){
             this.server.emit(validationFailedEvent, email);
             return callback(new Error(err && err.SMTPResponse || dnsErrorMessage));
         }
         validateViaLocal.call(this);
     }).bind(this));
 };
Example #7
0
DirectMailer.prototype._resolveMx = function(domain, callback){

    // Do not try to resolve the domain name if it is an IP address
    if(net.isIP(domain)){
        return callback(null, [{'priority': 10, 'exchange': domain}]);
    }

    dns.resolveMx(domain, callback);
};
Example #8
0
 function domainVerify() {
     dns.resolveMx(
                 self.name,
                 this.parallel()
             );
     dns.resolveCname(
                 self.name,
                 this.parallel()
             );
 },
Example #9
0
 return new Promise(function (fulfill, reject) {
   dns.resolveMx(host, function (err, addresses) {
     if (err) {
       reject(err);
     } else if (addresses.length === 0) {
       reject(new Error('MX Record nonexistent'));
     } else {
       fulfill();
     }
   });
 })
DirectMailer.prototype._resolveMx = function(domain, callback) {
    domain = domain.replace(/[\[\]]/g, '');

    // Do not try to resolve the domain name if it is an IP address
    if (net.isIP(domain)) {
        return callback(null, [{
            'priority': 0,
            'exchange': domain
        }]);
    }

    dns.resolveMx(domain, function(err, list) {
        if (err) {
            if (err.code === 'ENODATA') {
                // fallback to A
                dns.resolve4(domain, function(err, list) {
                    if (err) {
                        if (err.code === 'ENODATA') {
                            // fallback to AAAA
                            dns.resolve6(domain, function(err, list) {
                                if (err) {
                                    return callback(err);
                                }

                                // return the first resolved Ipv6 with priority 0
                                return callback(null, [].concat(list || []).map(function(entry) {
                                    return {
                                        'priority': 0,
                                        'exchange': entry
                                    };
                                }).slice(0, 1));
                            });
                        } else {
                            callback(err);
                        }
                        return;
                    }

                    // return the first resolved Ipv4 with priority 0
                    return callback(null, [].concat(list || []).map(function(entry) {
                        return {
                            'priority': 0,
                            'exchange': entry
                        };
                    }).slice(0, 1));
                });
            } else {
                callback(err);
            }
            return;
        }
        callback(null, list);
    });
};
Example #11
0
function getMX(cb){
    dns.resolveMx("gmail.com",function(err,mx){
        var highest;
        for(var i = 0; i < mx.length; i++){
            if(!highest || highest.priority > mx[i].priority){
                highest = mx[i];
            }
        }
        cb(highest.exchange);
    });
}
Example #12
0
TEST(function test_resolveMx_failure(done) {
  var req = dns.resolveMx('something.invalid', function(err, result) {
    assert.ok(err instanceof Error);
    assert.strictEqual(err.errno, 'ENOTFOUND');

    assert.strictEqual(result, undefined);

    done();
  });

  checkWrap(req);
});
Example #13
0
function getexchange (domain, cb) {
  dns.resolveMx(domain, function (err, addresses) {
    if (err) return cb(err);
    var resolver = {}
    addresses.reverse();
    for (var i=0;i<addresses.length;i++) {
      resolver[addresses[i].priority] = addresses[i].exchange;
    }
    var keys = Object.keys(resolver)
    keys.sort()
    cb(null, resolver[keys[0]])
  })
}
Example #14
0
 var validateViaDNS = function () {
     try {
         dns.resolveMx(domain, (function (err, addresses) {
             if (err || !addresses || !addresses.length) {
                 _this.emit(validationFailedEvent, email);
                 return reject(new Error(dnsErrorMessage));
             }
             validateViaLocal();
         }));
     } catch (e) {
         return reject(e);
     }
 };
Example #15
0
 var validateViaDNS = function () {
     if(!self.server.options.disableDNSValidation) {
         dnslib.resolveMx(domain, function(err, addresses){
             if(err || !addresses || !addresses.length){
                 self.server.emit(validationFailedEvent, email);
                 return callback(new Error(dnsErrorMessage));
             }
             return validateViaLocal();
         });
     } else {
         return validateViaLocal();
     }
 };
Example #16
0
    namespace.run(function () {
      namespace.set('test', 707);
      t.equal(namespace.get('test'), 707, "state has been mutated");

      dns.resolveMx('newrelic.com', function (err, addresses) {
        t.notOk(err, "lookup succeeded");
        t.ok(addresses.length > 0, "some results were found");

        t.equal(namespace.get('test'), 707,
                "mutated state has persisted to dns.resolveMx's callback");

        t.end();
      });
    });
Example #17
0
TEST(function test_resolveMx_failure(done) {
  dnsPromises.resolveMx(addresses.INVALID_HOST)
    .then(common.mustNotCall())
    .catch(common.expectsError({ errno: 'ENOTFOUND' }));

  const req = dns.resolveMx(addresses.INVALID_HOST, function(err, result) {
    assert.ok(err instanceof Error);
    assert.strictEqual(err.errno, 'ENOTFOUND');

    assert.strictEqual(result, undefined);

    done();
  });

  checkWrap(req);
});
Example #18
0
SMTPServerConnection.prototype._onCommandMAIL = function(mail){
    var match, email, domain;
    
    if(!this.hostNameAppearsAs){
        return this.client.send("503 5.5.1 Error: send HELO/EHLO first");
    }
    
    if(this.server.options.requireAuthentication && !this.authentication.authenticated){
        return this.client.send("530 5.5.1 Authentication Required");
    }
    
    if(this.envelope.from){
        return this.client.send("503 5.5.1 Error: nested MAIL command");
    }
    
    if(!(match = mail.match(/^from\:\s*<([^@>]+\@([^@>]+))>$/i))){
        return this.client.send("501 5.1.7 Bad sender address syntax");
    }
    
    email = match[1] || "";
    domain = (match[2] || "").toLowerCase();
    
    dnslib.resolveMx(domain, (function(err, addresses){
        if(err || !addresses || !addresses.length){
            return this.client.send("450 4.1.8 <"+email+">: Sender address rejected: Domain not found");
        }
        
        if(this.server.options.validateSender){
            this.server.emit("validateSender", this.envelope, email, (function(err){
                if(err){
                    return this.client.send("550 5.1.1 <"+email+">: Sender address rejected: User unknown in local sender table");
                }
                
                // force domain part to be lowercase
                email = email.substr(0, email.length - domain.length) + domain;
                this.envelope.from = email;
                this.client.send("250 2.1.0 Ok");
        
            }).bind(this));
        }else{
            // force domain part to be lowercase
            email = email.substr(0, email.length - domain.length) + domain;
            this.envelope.from = email;
            this.client.send("250 2.1.0 Ok");
        }
    }).bind(this));  
};
Example #19
0
SMTPServerConnection.prototype._onCommandRCPT = function(mail){
    var match, email, domain;
    
    if(!this.envelope.from){
        return this.client.send("503 5.5.1 Error: need MAIL command");
    }
    
    if(!(match = mail.match(/^to\:\s*<([^@>]+\@([^@>]+))>$/i))){
        return this.client.send("501 5.1.7 Bad recipient address syntax");
    }
    
    email = match[1] || "";
    domain = (match[2] || "").toLowerCase();
    
    dnslib.resolveMx(domain, (function(err, addresses){
        if(err || !addresses || !addresses.length){
            return this.client.send("450 4.1.8 <"+email+">: Recipient address rejected: Domain not found");
        }
        
        if(this.server.options.validateRecipients){
            this.server.emit("validateRecipient", this.envelope, email, (function(err){
                if(err){
                    return this.client.send("550 5.1.1 <"+email+">: Recipient address rejected: User unknown in local recipient table");
                }
                
                // force domain part to be lowercase
                email = email.substr(0, email.length - domain.length) + domain;
                
                // add to recipients list
                if(this.envelope.to.indexOf(email)<0){
                    this.envelope.to.push(email);
                }
                this.client.send("250 2.1.0 Ok");
            }).bind(this));
        }else{
            // force domain part to be lowercase
            email = email.substr(0, email.length - domain.length) + domain;
            
            // add to recipients list
            if(this.envelope.to.indexOf(email)<0){
                this.envelope.to.push(email);
            }
            this.client.send("250 2.1.0 Ok");
        }
    }).bind(this));  
};
Example #20
0
var get_smtp_servers = function(recipient, cb) {

  var domain = recipient.replace(/.*@/, '');
  dns.resolveMx(domain, function(err, addresses) {

    if (err) return cb(err);

    var hosts = [];
    var sorted = addresses.sort(function(a, b){ return (a.priority > b.priority) });

    sorted.forEach(function(host){
      hosts.push(host.exchange);
    });

    cb(null, hosts);
  });

};
exports.hook_mail = function(next, connection, params) {
    var mail_from    = params[0];

    // Check for MAIL FROM without an @ first - ignore those here
    if (!mail_from.host) {
        return next();
    }

    var called_next  = 0;
    var timeout_id   = 0;
    var plugin       = this;
    var domain       = mail_from.host;
    var config       = this.config.get('mail_from.is_resolvable.ini');
    var timeout      = config.general && (config.general['timeout']     || 60);
    var timeout_msg  = config.general && (config.general['timeout_msg'] || '');

    // Just in case DNS never comes back (UDP), we should DENYSOFT.
    timeout_id = setTimeout(function () {
        plugin.loginfo('timed out when looking up ' + domain +
            '\'s MX record. Disconnecting.');
        called_next++;
        return next(DENYSOFT, timeout_msg);
    }, timeout * 1000);

    dns.resolveMx(domain, function(err, addresses) {
        if (called_next) {
            // This happens when we've called next() from our plugin timeout
            // handler, but we eventually get a response from DNS.  We do not
            // want to call next() again, so we just return. 
            return;
        }
        if (err && err.code != dns.NXDOMAIN && err.code != 'ENOTFOUND') {
            plugin.logerror("DNS Error: " + err);
            clearTimeout(timeout_id);
            return next(DENYSOFT, "Temporary resolver error");
        }
        if (addresses && addresses.length) {
            clearTimeout(timeout_id);
            return next();
        }
        clearTimeout(timeout_id);
        return next(DENYSOFT, "No MX for your FROM address");
    });
}
Example #22
0
	this.get_smtp_servers = function(callback){

		var domain = this.recipient.replace(/.*@/, '');
		// console.log(domain);

		dns.resolveMx(domain, function(err, addresses) {

			if (err) return callback(err);

			var hosts = [];
			var sorted = addresses.sort(function(a, b){ return (a.priority > b.priority); });

			sorted.forEach(function(host){
				hosts.push(host.exchange);
			});

			callback(null, hosts);

		});

	};
Example #23
0
TEST(function test_resolveMx(done) {
  const req = dns.resolveMx('gmail.com', function(err, result) {
    assert.ifError(err);
    assert.ok(result.length > 0);

    for (let i = 0; i < result.length; i++) {
      const item = result[i];
      assert.ok(item);
      assert.strictEqual(typeof item, 'object');

      assert.ok(item.exchange);
      assert.strictEqual(typeof item.exchange, 'string');

      assert.strictEqual(typeof item.priority, 'number');
    }

    done();
  });

  checkWrap(req);
});
Example #24
0
TEST(function test_resolveMx(done) {
  var req = dns.resolveMx('gmail.com', function(err, result) {
    if (err) throw err;

    assert.ok(result.length > 0);

    for (var i = 0; i < result.length; i++) {
      var item = result[i];
      assert.ok(item);
      assert.ok(typeof item === 'object');

      assert.ok(item.exchange);
      assert.ok(typeof item.exchange === 'string');

      assert.ok(typeof item.priority === 'number');
    }

    done();
  });

  checkWrap(req);
});
Example #25
0
/*
    Resolve MX
    @domain {String}
    @callback {Function} :: callback(error, socket);
*/
/**
 * Resolve MX record
 * @param  {String}   domain   Domain name.
 * @param  {ResolveMxCallback} callback Callback.
 */
function resolveMx(domain, callback) {
    dns.resolveMx(domain, function(err, data) {

        if (err) {
            callback(err, data);
            return;
        }

        if (!data || data.length === 0) {
            callback(new Error(errors.resolve + domain));
            return;
        }

        data.sort(function(a, b) {
            return a.priority < b. priority;
        });

        function tryConnect(index) {

            if (index >= data.length) {
                callback(new Error(errors.connection));
                return;
            }

            var sock = net.createConnection(25, data[index].exchange);

            sock.on('error', function(err) {
                tryConnect(++index);
            });

            sock.on('connect', function() {
                sock.removeAllListeners('error');
                callback(null, sock);
            });
        }

        tryConnect(0);
    });
}
Example #26
0
module.exports = function isGmail(email, callback) {
  if ((typeof email !== 'string') || !isEmail(email)) {
    process.nextTick(function () {
      callback(false);
    });
  } else {
    var domain = email.split('@')[1];
    if (~['gmail.com', 'google.com', 'googlemail.com'].indexOf(domain)) {
      process.nextTick(function () {
        callback(true);
      });
    } else {
      dns.resolveMx(domain, function (err, result) {
        callback(
          err ? false : result.some(function (item) {
            return item.exchange.match(/google(mail)?\.com$/i);
          })
        );
      });
    }
  }
};
Example #27
0
TEST(async function test_resolveMx(done) {
  function validateResult(result) {
    assert.ok(result.length > 0);

    for (const item of result) {
      assert.strictEqual(typeof item, 'object');
      assert.ok(item.exchange);
      assert.strictEqual(typeof item.exchange, 'string');
      assert.strictEqual(typeof item.priority, 'number');
    }
  }

  validateResult(await dnsPromises.resolveMx(addresses.MX_HOST));

  const req = dns.resolveMx(addresses.MX_HOST, function(err, result) {
    assert.ifError(err);
    validateResult(result);
    done();
  });

  checkWrap(req);
});
Example #28
0
"use strict";var net=require("net");var tls=require("tls");var events=require("events");var dns=require("dns");var fs=require("fs");var path=require("path");var CRLF="\r\n";var UNDEFINED="undefined";var errors={notvalid:"E-mail address is not valid",resolve:"Cannot resolve MX of ",connection:"Cannot connect to any SMTP server."};function Mailer(){this.debug=false;this.Message=Message;this.Mail=Message}Mailer.prototype.__proto__=Object.create(events.EventEmitter.prototype,{constructor:{value:Mailer,enumberable:false}});Mailer.prototype.create=function(subject,body){return new Message(subject,body)};function resolveMx(domain,callback){dns.resolveMx(domain,function(err,data){if(err){callback(err,data);return}if(!data||data.length===0){callback(new Error(errors.resolve+domain));return}data.sort(function(a,b){return a.priority<b.priority});function tryConnect(index){if(index>=data.length){callback(new Error(errors.connection));return}var sock=net.createConnection(25,data[index].exchange);sock.on("error",function(err){tryConnect(++index)});sock.on("connect",function(){callback(null,sock)})}tryConnect(0)})}function Message(subject,body){this.subject=subject||"";this.body=body||"";this.files=[];this.addressTo=[];this.addressReply=[];this.addressCC=[];this.addressBCC=[];this.addressFrom={name:"",address:""};this.callback=null;this.closed=false}Message.prototype.sender=function(address,name){return this.from(address,name)};Message.prototype.from=function(address,name){if(!address.isEmail())throw new Error(errors.notvalid);var self=this;self.addressFrom.name=name||"";self.addressFrom.address=address;return self};Message.prototype.to=function(address){if(!address.isEmail())throw new Error(errors.notvalid);var self=this;self.addressTo.push(address);return self};Message.prototype.cc=function(address){if(!address.isEmail())throw new Error(errors.notvalid);var self=this;self.addressCC.push(address);return self};Message.prototype.bcc=function(address){if(!address.isEmail())throw new Error(errors.notvalid);var self=this;self.addressBCC.push(address);return self};Message.prototype.reply=function(address){if(!address.isEmail())throw new Error(errors.notvalid);var self=this;self.addressReply.push(address);return self};Message.prototype.attachment=function(filename,name){var self=this;if(name===undefined)name=path.basename(filename);self.files.push({name:name,filename:filename,contentType:framework_utils.getContentType(path.extname(name))});return self};Message.prototype.attachmentInline=function(filename,name,contentId){var self=this;if(name===undefined)name=path.basename(filename);self.files.push({name:name,filename:filename,contentType:utils.getContentType(path.extname(name)),disposition:"inline",contentId:contentId});return self};Message.prototype.send=function(smtp,options,fnCallback){var self=this;smtp=smtp||null;if(typeof options==="function"){var tmp=fnCallback;fnCallback=options;options=tmp}self.callback=fnCallback;options=framework_utils.copy(options,{secure:false,port:25,user:"",password:"",timeout:1e4});if(smtp===null||smtp===""){smtp=getHostName(self.addressFrom.address);resolveMx(smtp,function(err,socket){if(err){mailer.emit("error",err,self);if(fnCallback)fnCallback(err);return}socket.on("error",function(err){mailer.emit("error",err,self);if(fnCallback)fnCallback(err)});self._send(socket,options)});return self}var socket;if(options.secure){var internal=framework_utils.copy(options);internal.host=smtp;socket=tls.connect(internal,function(){self._send(this,options)})}else socket=net.createConnection(options.port,smtp);socket.on("error",function(err){socket.destroy();self.closed=true;if(err.stack.indexOf("ECONNRESET")!==-1)mailer.emit("error",err,self)});socket.on("clientError",function(err){mailer.emit("error",err,self)});socket.on("connect",function(){if(!options.secure)self._send(socket,options)});return self};Message.prototype._send=function(socket,options){var self=this;var command="";var buffer=[];var message=[];var host=getHostName(self.addressFrom.address);var date=new Date;var boundary="--totaljs"+date.getTime();var isAuthenticated=false;var isAuthorization=false;var authType="";var auth=[];var err=null;var ending=null;mailer.emit("send",self);socket.setTimeout(options.timeout||5e3,function(){self.closed=true;mailer.emit("error",new Error(framework_utils.httpStatus(408)),self);if(socket!==null)socket.destroy();socket=null});socket.setEncoding("utf8");var write=function(line){if(self.closed)return;if(mailer.debug)console.log("SEND",line);socket.write(line+CRLF)};buffer.push("MAIL FROM: <"+self.addressFrom.address+">");message.push("Message-ID: <"+GUID()+"@WIN-"+s4()+">");message.push("MIME-Version: 1.0");message.push("From: "+(self.addressFrom.name.length>0?unicode_encode(self.addressFrom.name)+" <"+self.addressFrom.address+">":self.addressFrom.address));var length=self.addressTo.length;var builder="";if(length>0){for(var i=0;i<length;i++){var mail="<"+self.addressTo[i]+">";buffer.push("RCPT TO: "+mail);builder+=(builder!==""?", ":"")+mail}message.push("To: "+builder);builder=""}length=self.addressCC.length;if(length>0){for(var i=0;i<length;i++){var mail="<"+self.addressCC[i]+">";buffer.push("RCPT TO: "+mail);builder+=(builder!==""?", ":"")+mail}message.push("Cc: "+builder);builder=""}length=self.addressBCC.length;if(length>0){for(var i=0;i<length;i++)buffer.push("RCPT TO: <"+self.addressBCC[i]+">")}buffer.push("DATA");buffer.push("QUIT");buffer.push("");message.push("Date: "+date.toUTCString());message.push("Subject: "+unicode_encode(self.subject));length=self.addressReply.length;if(length>0){for(var i=0;i<length;i++)builder+=(builder!==""?", ":"")+"<"+self.addressReply[i]+">";message.push("Reply-To: "+builder);builder=""}message.push("Content-Type: multipart/mixed; boundary="+boundary);message.push("");message.push("--"+boundary);message.push("Content-Type: "+(self.body.indexOf("<")!==-1&&self.body.lastIndexOf(">")!==-1?"text/html":"text/plain")+"; charset=utf-8");message.push("Content-Transfer-Encoding: base64");message.push("");message.push(prepareBASE64(new Buffer(self.body.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n")).toString("base64")));length=self.files.length;if(mailer.debug){socket.on("end",function(){self.closed=true;if(socket)socket.destroy()})}socket.on("data",function(data){if(self.closed)return;var response=data.toString().split(CRLF);var length=response.length;for(var i=0;i<length;i++){var line=response[i];if(line==="")continue;if(socket)socket.emit("line",line)}});socket.on("line",function(line){line=line.toUpperCase();if(mailer.debug)console.log("<–––",line);var code=parseInt(line.match(/\d+/)[0],10);if(code===250&&!isAuthorization){if(line.indexOf("AUTH LOGIN PLAIN")!==-1||line.indexOf("AUTH PLAIN LOGIN")!==-1||options.user&&options.password){authType="plain";isAuthorization=true;if(line.indexOf("XOAUTH")===-1){auth.push("AUTH LOGIN");auth.push(new Buffer(options.user).toString("base64"));auth.push(new Buffer(options.password).toString("base64"))}else auth.push("AUTH PLAIN "+new Buffer("\x00"+options.user+"\x00"+options.password).toString("base64"))}}if(line.substring(3,4)==="-"){return}if(!isAuthenticated&&isAuthorization){isAuthenticated=true;code=334}switch(code){case 220:command=/\besmtp\b/i.test(line)?"EHLO":"HELO";write(command+" "+host);break;case 221:case 250:case 251:case 235:write(buffer.shift());if(buffer.length===0){mailer.emit("success",self);if(self.callback)self.callback(null);ending=setTimeout(function(){if(socket!==null)socket.destroy();socket=null},500)}break;case 334:var value=auth.shift();if(value===undefined){err=new Error("Forbidden.");mailer.emit("error",err,self);if(self.callback)self.callback(err);if(socket!==null)socket.destroy();socket=null;break}write(value);break;case 354:write(message.join(CRLF));if(self.files.length>0){message=null;self._writeAttachment(write,boundary,socket);return}write("--"+boundary+"--");write("");write(".");message=null;break;default:if(code<400)break;err=new Error(line);if(socket!==null)socket.destroy();socket=null;mailer.emit("error",err,self);if(self.callback)self.callback(err);break}})};Message.prototype._writeAttachment=function(write,boundary,socket){var self=this;var attachment=self.files.shift();if(attachment===undefined){write("--"+boundary+"--");write("");write(".");return}var name=attachment.name;var stream=fs.createReadStream(attachment.filename,{encoding:"base64"});var message=[];var ext=path.extname(attachment.filename);message.push("--"+boundary);if(attachment.contentId){message.push('Content-Disposition: inline; filename="'+name+'"');message.push("Content-ID: <"+attachment.contentId+">")}else{message.push('Content-Disposition: attachment; filename="'+name+'"')}message.push("Content-Type: application/octet-stream;");message.push("Content-Transfer-Encoding: base64");message.push(CRLF);write(message.join(CRLF));stream.on("data",function(buf){var length=buf.length;var count=0;var beg=0;while(count<length){count+=68;if(count>length)count=length;write(buf.slice(beg,count).toString("base64"));beg=count}});stream.on("end",function(){write(CRLF);self._writeAttachment(write,boundary,socket)});return self};function prepareBASE64(value){var index=0;var output="";var length=value.length;while(index<length){var max=index+68;if(max>length)max=length;output+=value.substring(index,max)+"\n";index=max}return output}function getHostName(address){return address.substring(address.indexOf("@")+1)}function s4(){return Math.floor((1+Math.random())*65536).toString(16).substring(1).toUpperCase()}function GUID(){return s4()+s4()+"-"+s4()+"-"+s4()+"-"+s4()+"-"+s4()+s4()+s4()}function unicode_encode(val){if(!val)return"";return"=?utf-8?B?"+new Buffer(val).toString("base64")+"?="}var mailer=new Mailer;module.exports=mailer;
Example #29
0
exports.hook_mail = function (next, connection, params) {
    const plugin    = this;
    const mail_from = params[0];
    const txn       = connection.transaction;
    const results   = txn.results;

    // Check for MAIL FROM without an @ first - ignore those here
    if (!mail_from.host) {
        results.add(plugin, {skip: 'null host'});
        return next();
    }

    let called_next  = 0;
    const domain       = mail_from.host;
    const c            = plugin.cfg.main;
    const timeout_id   = setTimeout(() => {
        // DNS answer didn't return (UDP)
        connection.loginfo(plugin, 'timed out resolving MX for ' + domain);
        called_next++;
        if (txn) results.add(plugin, {err: 'timeout(' + domain + ')'});
        next(DENYSOFT, 'Temporary resolver error (timeout)');
    }, c.timeout * 1000);

    function mxDone (code, reply) {
        if (called_next) return;
        clearTimeout(timeout_id);
        called_next++;
        next(code, reply);
    }

    // IS: IPv6 compatible
    dns.resolveMx(domain, (err, addresses) => {
        if (!txn) return;
        if (err && plugin.mxErr(connection, domain, 'MX', err, mxDone)) return;

        if (!addresses || !addresses.length) {
            // Check for implicit MX 0 record
            return plugin.implicit_mx(connection, domain, mxDone);
        }

        // Verify that the MX records resolve to valid addresses
        let records = {};
        let pending_queries = 0;
        function check_results () {
            if (pending_queries !== 0) return;

            records = Object.keys(records);
            if (records && records.length) {
                connection.logdebug(plugin, domain + ': ' + records);
                results.add(plugin, {pass: '******'});
                return mxDone();
            }
            results.add(plugin, {fail: 'has_fwd_dns'});
            return mxDone(((c.reject_no_mx) ? DENY : DENYSOFT),
                'MX without A/AAAA records');
        }

        addresses.forEach(addr => {
            // Handle MX records that are IP addresses
            // This is invalid - but a lot of MTAs allow it.
            if (net_utils.get_ipany_re('^\\[','\\]$','').test(addr.exchange)) {
                connection.logwarn(plugin, domain + ': invalid MX ' +
                        addr.exchange);
                if (c.allow_mx_ip) {
                    records[addr.exchange] = 1;
                }
                return;
            }
            pending_queries++;
            net_utils.get_ips_by_host(addr.exchange, (err2, addresses2) => {
                pending_queries--;
                if (!txn) return;
                if (err2 && err2.length === 2) {
                    results.add(plugin, {msg: err2[0].message});
                    connection.logdebug(plugin, domain + ': MX ' +
                            addr.priority + ' ' + addr.exchange +
                            ' => ' + err2[0].message);
                    check_results();
                    return;
                }
                connection.logdebug(plugin, domain + ': MX ' + addr.priority +
                        ' ' + addr.exchange + ' => ' + addresses2);
                for (let i=0; i < addresses2.length; i++) {
                    // Ignore anything obviously bogus
                    if (net.isIPv4(addresses2[i])){
                        if (plugin.re_bogus_ip.test(addresses2[i])) {
                            connection.logdebug(plugin, addr.exchange +
                                    ': discarding ' + addresses2[i]);
                            continue;
                        }
                    }
                    if (net.isIPv6(addresses2[i])){
                        if (net_utils.ipv6_bogus(addresses2[i])) {
                            connection.logdebug(plugin, addr.exchange +
                                    ': discarding ' + addresses2[i]);
                            continue;
                        }
                    }
                    records[addresses2[i]] = 1;
                }
                check_results();
            });
        });
        // In case we don't run any queries
        check_results();
    });
}
Example #30
0
exports.lookup_mx = function lookup_mx (domain, cb) {
    var mxs = [];
    
    // Possible DNS errors
    // NODATA
    // FORMERR
    // BADRESP
    // NOTFOUND
    // BADNAME
    // TIMEOUT
    // CONNREFUSED
    // NOMEM
    // DESTRUCTION
    // NOTIMP
    // EREFUSED
    // SERVFAIL
    
    // default wrap_mx just returns our object with "priority" and "exchange" keys
    var wrap_mx = function (a) { return a };
    var process_dns = function (err, addresses) {
        if (err) {
            if (err.code === 'ENODATA') {
                // Most likely this is a hostname with no MX record
                // Drop through and we'll get the A record instead.
                return 0;
            }
            cb(err);
        }
        else if (addresses && addresses.length) {
            for (var i=0,l=addresses.length; i < l; i++) {
                var mx = wrap_mx(addresses[i]);
                // hmail.logdebug("Got an MX from DNS: " + hmail.todo.domain + " => " + mx.priority + " " + mx.exchange);
                mxs.push(mx);
            }
            cb(null, mxs);
        }
        else {
            // return zero if we need to keep trying next option
            return 0;
        }
        return 1;
    };
    
    dns.resolveMx(domain, function(err, addresses) {
        if (process_dns(err, addresses)) {
            return;
        }
        
        // if MX lookup failed, we lookup an A record. To do that we change
        // wrap_mx() to return same thing as resolveMx() does.
        wrap_mx = function (a) { return {priority:0,exchange:a} };

        dns.resolve(domain, function(err, addresses) {
            if (process_dns(err, addresses)) {
                return;
            }
            var err = new Error("Found nowhere to deliver to");
            err.code = 'NOMX';
            cb(err);
        });
    });
}