mirror of
https://github.com/mgerb/mywebsite
synced 2026-01-11 18:32:50 +00:00
updated bunch of file paths and changed the way posts are loaded
This commit is contained in:
20
node_modules/nodemailer-direct-transport/.jshintrc
generated
vendored
Normal file
20
node_modules/nodemailer-direct-transport/.jshintrc
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"indent": 4,
|
||||
"node": true,
|
||||
"globalstrict": true,
|
||||
"evil": true,
|
||||
"unused": true,
|
||||
"undef": true,
|
||||
"newcap": true,
|
||||
"esnext": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"expr": true,
|
||||
|
||||
"predef": [
|
||||
"describe",
|
||||
"it",
|
||||
"beforeEach",
|
||||
"afterEach"
|
||||
]
|
||||
}
|
||||
2
node_modules/nodemailer-direct-transport/.npmignore
generated
vendored
Normal file
2
node_modules/nodemailer-direct-transport/.npmignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
.travis.yml
|
||||
tests
|
||||
15
node_modules/nodemailer-direct-transport/CHANGELOG.md
generated
vendored
Normal file
15
node_modules/nodemailer-direct-transport/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## v1.1.0 2015-10-08
|
||||
|
||||
If MX record is not found, fallback to A or AAAA
|
||||
|
||||
## v1.0.2 2015-03-09
|
||||
|
||||
Bumped smtp-connection version and replaced simplesmtp based tests with smtp-server based ones.
|
||||
|
||||
## v1.0.0 2014-07-30
|
||||
|
||||
Fixed a bug with stream buffering. Uses [mail.resolveContent](https://github.com/andris9/Nodemailer#resolvecontent) provided by Nodemailer v1.1.
|
||||
|
||||
As the change includes a method from Nodemailer 1.1 and not 1.0, then changed the version scheme to use proper semver instead of 0.x.
|
||||
29
node_modules/nodemailer-direct-transport/Gruntfile.js
generated
vendored
Normal file
29
node_modules/nodemailer-direct-transport/Gruntfile.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
module.exports = function(grunt) {
|
||||
'use strict';
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
all: ['src/*.js', 'test/*.js'],
|
||||
options: {
|
||||
jshintrc: '.jshintrc'
|
||||
}
|
||||
},
|
||||
|
||||
mochaTest: {
|
||||
all: {
|
||||
options: {
|
||||
reporter: 'spec'
|
||||
},
|
||||
src: ['test/*-test.js']
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Load the plugin(s)
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-mocha-test');
|
||||
|
||||
// Tasks
|
||||
grunt.registerTask('default', ['jshint', 'mochaTest']);
|
||||
};
|
||||
19
node_modules/nodemailer-direct-transport/LICENSE
generated
vendored
Normal file
19
node_modules/nodemailer-direct-transport/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2014 Andris Reinman
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
60
node_modules/nodemailer-direct-transport/README.md
generated
vendored
Normal file
60
node_modules/nodemailer-direct-transport/README.md
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
# Direct SMTP transport module for Nodemailer
|
||||
|
||||
Applies for Nodemailer v1.x and not for v0.x where transports are built-in.
|
||||
|
||||
## Usage
|
||||
|
||||
Install with npm
|
||||
|
||||
npm install nodemailer-direct-transport
|
||||
|
||||
Require to your script
|
||||
|
||||
```javascript
|
||||
var nodemailer = require('nodemailer');
|
||||
var directTransport = require('nodemailer-direct-transport');
|
||||
```
|
||||
|
||||
Create a Nodemailer transport object
|
||||
|
||||
```javascript
|
||||
var transporter = nodemailer.createTransport(directTransport(options))
|
||||
```
|
||||
|
||||
Where
|
||||
|
||||
* **options** defines connection data
|
||||
* **options.name** hostname to be used when introducing the client to the MX server
|
||||
* **options.debug** if true, the connection emits all traffic between client and server as 'log' events
|
||||
|
||||
**Example**
|
||||
|
||||
```javascript
|
||||
var transport = nodemailer.createTransport(directTransport());
|
||||
```
|
||||
|
||||
## send callback
|
||||
|
||||
Send callback includes the following arguments
|
||||
|
||||
* **error** if the mail was not sent
|
||||
* **error.errors** is an array of error responses (one response for one MX exchange)
|
||||
* **error.errors[].recipients** an array of failed recipients
|
||||
* **error.errors[].response** Error response from the SMTP server
|
||||
* **info** if at least one mail was sent or is pending
|
||||
* **info.accepted** an array of recipients that were accepted
|
||||
* **info.rejected** an array of recipients that were rejected
|
||||
* **info.pending** an arrray of pending recipient objects (messages that were not rejected permanently and are retried later)
|
||||
* **info.pending[].recipients** an array of recipient addresses that are still pending
|
||||
* **info.pending[].response** Response from the SMTP server
|
||||
* **info.errors** An array of errors (for these exhanges that rejected mail)
|
||||
|
||||
## Issues
|
||||
|
||||
Direct transport is very inefficient as it queues all e-mails to be sent into memory. Additionally, if a message is not yet sent and the process is closed, all data about queued messages is lost. Thus direct transport is only suitable for low throughput systems, where the message can be processed immediatelly.
|
||||
|
||||
While not being 100% reliable (remember - if process exits, entire queue is lost), direct transport can still handle sending errors, graylisting and such. If a message can not be sent, it is requeued and retried later.
|
||||
|
||||
## License
|
||||
|
||||
**MIT**
|
||||
85
node_modules/nodemailer-direct-transport/package.json
generated
vendored
Normal file
85
node_modules/nodemailer-direct-transport/package.json
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"_args": [
|
||||
[
|
||||
"nodemailer-direct-transport@^1.1.0",
|
||||
"/home/mitchell/Desktop/test-mywebsite/mywebsite/node_modules/nodemailer"
|
||||
]
|
||||
],
|
||||
"_from": "nodemailer-direct-transport@>=1.1.0 <2.0.0",
|
||||
"_id": "nodemailer-direct-transport@1.1.0",
|
||||
"_inCache": true,
|
||||
"_installable": true,
|
||||
"_location": "/nodemailer-direct-transport",
|
||||
"_nodeVersion": "4.1.1",
|
||||
"_npmUser": {
|
||||
"email": "andris@kreata.ee",
|
||||
"name": "andris"
|
||||
},
|
||||
"_npmVersion": "2.14.4",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"name": "nodemailer-direct-transport",
|
||||
"raw": "nodemailer-direct-transport@^1.1.0",
|
||||
"rawSpec": "^1.1.0",
|
||||
"scope": null,
|
||||
"spec": ">=1.1.0 <2.0.0",
|
||||
"type": "range"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/nodemailer"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-1.1.0.tgz",
|
||||
"_shasum": "a2f78708ee6f16ea0573fc82949d138ff172f624",
|
||||
"_shrinkwrap": null,
|
||||
"_spec": "nodemailer-direct-transport@^1.1.0",
|
||||
"_where": "/home/mitchell/Desktop/test-mywebsite/mywebsite/node_modules/nodemailer",
|
||||
"author": {
|
||||
"name": "Andris Reinman"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/andris9/nodemailer-direct-transport/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"smtp-connection": "^1.3.1"
|
||||
},
|
||||
"description": "Direct transport for Nodemailer",
|
||||
"devDependencies": {
|
||||
"chai": "^3.3.0",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-contrib-jshint": "^0.11.3",
|
||||
"grunt-mocha-test": "^0.12.7",
|
||||
"mocha": "^2.3.3",
|
||||
"sinon": "^1.17.1",
|
||||
"smtp-server": "^1.6.0"
|
||||
},
|
||||
"directories": {},
|
||||
"dist": {
|
||||
"shasum": "a2f78708ee6f16ea0573fc82949d138ff172f624",
|
||||
"tarball": "http://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-1.1.0.tgz"
|
||||
},
|
||||
"gitHead": "349ea2df54e3051de02d611bc94bbbaa4c264435",
|
||||
"homepage": "http://github.com/andris9/nodemailer-direct-transport",
|
||||
"keywords": [
|
||||
"Nodemailer",
|
||||
"SMTP"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "src/direct-transport.js",
|
||||
"maintainers": [
|
||||
{
|
||||
"name": "andris",
|
||||
"email": "andris@node.ee"
|
||||
}
|
||||
],
|
||||
"name": "nodemailer-direct-transport",
|
||||
"optionalDependencies": {},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/andris9/nodemailer-direct-transport.git"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt"
|
||||
},
|
||||
"version": "1.1.0"
|
||||
}
|
||||
441
node_modules/nodemailer-direct-transport/src/direct-transport.js
generated
vendored
Normal file
441
node_modules/nodemailer-direct-transport/src/direct-transport.js
generated
vendored
Normal file
@@ -0,0 +1,441 @@
|
||||
'use strict';
|
||||
|
||||
var createQueue = require('./message-queue');
|
||||
var SMTPConnection = require('smtp-connection');
|
||||
var dns = require('dns');
|
||||
var net = require('net');
|
||||
var os = require('os');
|
||||
var util = require('util');
|
||||
var packageData = require('../package.json');
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
|
||||
// Expose to the world
|
||||
module.exports = function(options) {
|
||||
return new DirectMailer(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new DirectMailer instance. Provides method 'send' to queue
|
||||
* outgoing e-mails. The queue is processed in the background.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} [options] Optional options object
|
||||
*/
|
||||
function DirectMailer(options) {
|
||||
EventEmitter.call(this);
|
||||
this._options = options || {};
|
||||
this._queue = createQueue();
|
||||
this._started = false;
|
||||
this._lastId = 0;
|
||||
|
||||
// temporary object
|
||||
var connection = new SMTPConnection({});
|
||||
|
||||
this.name = 'SMTP (direct)';
|
||||
this.version = packageData.version + '[client:' + connection.version + ']';
|
||||
}
|
||||
util.inherits(DirectMailer, EventEmitter);
|
||||
|
||||
// Adds a dynamic property 'length'
|
||||
Object.defineProperty(DirectMailer.prototype, 'length', {
|
||||
get: function() {
|
||||
return this._queue._instantQueue.length + this._queue._sortedQueue.length;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Adds an outgoing message to the queue. Recipient addresses are sorted
|
||||
* by the receiving domain and for every domain, a copy of the message is queued.
|
||||
*
|
||||
* If input is deemed invalid, an error is thrown, so be ready to catch these
|
||||
* when calling directmail.send(...)
|
||||
*
|
||||
* @param {Object} mail Mail object
|
||||
* @param {Function} callback Callback function
|
||||
*/
|
||||
DirectMailer.prototype.send = function(mail, callback) {
|
||||
|
||||
var envelope = mail.data.envelope || mail.message.getEnvelope();
|
||||
var domainEnvelopes = {};
|
||||
|
||||
if (!envelope.from) {
|
||||
return callback(new Error('"From" address missing'));
|
||||
}
|
||||
|
||||
envelope.to = [].concat(envelope.to || []);
|
||||
|
||||
if (!envelope.to.length) {
|
||||
return callback('"Recipients" addresses missing');
|
||||
}
|
||||
|
||||
// We cant't run existing streams more than once so we need to change these
|
||||
// to buffers. Filenames, URLs etc are not affected – for every
|
||||
// message copy a new file stream will be created
|
||||
this._clearStreams(mail, function() {
|
||||
|
||||
this._formatMessage(mail.message);
|
||||
|
||||
envelope.to.forEach(function(recipient) {
|
||||
recipient = (recipient || '').toString();
|
||||
|
||||
var domain = (recipient.split('@').pop() || '').toLowerCase().trim();
|
||||
|
||||
if (!domainEnvelopes[domain]) {
|
||||
domainEnvelopes[domain] = {
|
||||
from: envelope.from,
|
||||
to: [recipient]
|
||||
};
|
||||
} else if (domainEnvelopes[domain].to.indexOf(recipient) < 0) {
|
||||
domainEnvelopes[domain].to.push(recipient);
|
||||
}
|
||||
});
|
||||
|
||||
var returned = 0;
|
||||
var domains = Object.keys(domainEnvelopes);
|
||||
var combinedInfo = {
|
||||
accepted: [],
|
||||
rejected: [],
|
||||
pending: [],
|
||||
errors: [],
|
||||
envelope: mail.data.envelope || mail.message.getEnvelope()
|
||||
};
|
||||
|
||||
domains.forEach((function(domain) {
|
||||
var called = false;
|
||||
var id = ++this._lastId;
|
||||
var item = {
|
||||
envelope: domainEnvelopes[domain],
|
||||
data: mail.data,
|
||||
message: mail.message,
|
||||
domain: domain,
|
||||
id: id,
|
||||
callback: function(err, info) {
|
||||
if (called) {
|
||||
this._log('Callback for #%s already called. Updated values: %s', id, JSON.stringify(err || info));
|
||||
return;
|
||||
}
|
||||
|
||||
called = true;
|
||||
returned++;
|
||||
|
||||
if (err) {
|
||||
combinedInfo.errors.push(err);
|
||||
if (err.recipients) {
|
||||
combinedInfo.rejected = combinedInfo.rejected.concat(err.recipients || []);
|
||||
}
|
||||
} else if (info) {
|
||||
combinedInfo.accepted = combinedInfo.accepted.concat(info.accepted || []);
|
||||
combinedInfo.rejected = combinedInfo.rejected.concat(info.rejected || []);
|
||||
combinedInfo.pending = combinedInfo.pending.concat(info.pending || []);
|
||||
combinedInfo.messageId = info.messageId;
|
||||
}
|
||||
|
||||
if (returned >= domains.length) {
|
||||
if (combinedInfo.errors.length === domains.length) {
|
||||
var error = new Error('Sending failed');
|
||||
error.errors = combinedInfo.errors;
|
||||
callback(error);
|
||||
} else {
|
||||
callback(null, combinedInfo);
|
||||
}
|
||||
}
|
||||
}.bind(this)
|
||||
};
|
||||
|
||||
this._queue.insert(item);
|
||||
}).bind(this));
|
||||
|
||||
// start send loop if needed
|
||||
if (!this._started) {
|
||||
this._started = true;
|
||||
|
||||
// do not start the loop before current execution context is finished
|
||||
setImmediate(this._loop.bind(this));
|
||||
}
|
||||
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Emit a log event
|
||||
*/
|
||||
DirectMailer.prototype._log = function( /*str, arg1, arg2, ..., argN*/ ) {
|
||||
if (!this._options.debug) {
|
||||
return;
|
||||
}
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
this.emit('log', {
|
||||
type: 'direct',
|
||||
message: util.format.apply(util, args)
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Looping function to fetch a message from the queue and send it.
|
||||
*/
|
||||
DirectMailer.prototype._loop = function() {
|
||||
|
||||
// callback is fired when a message is added to the queue
|
||||
this._queue.get((function(data) {
|
||||
|
||||
this._log('Retrieved message #%s from the queue, resolving %s', data.id, data.domain);
|
||||
|
||||
// Resolve destination MX server
|
||||
this._resolveMx(data.domain, (function(err, list) {
|
||||
|
||||
if (err) {
|
||||
this._log('Resolving %s for #%s failed', data.domain, data.id);
|
||||
this._log(err);
|
||||
} else if (!list || !list.length) {
|
||||
this._log('Could not resolve any MX servers for %s', data.domain);
|
||||
}
|
||||
if (err || !list || !list.length) {
|
||||
data.callback(err || new Error('Could not resolve MX for ' + data.domain));
|
||||
return setImmediate(this._loop.bind(this));
|
||||
}
|
||||
|
||||
// Sort MX list by priority field
|
||||
list.sort(function(a, b) {
|
||||
return (a && a.priority || 0) - (b && b.priority || 0);
|
||||
});
|
||||
|
||||
// Use the first server on the list
|
||||
var exchange = list[0] && list[0].exchange;
|
||||
|
||||
this._log('%s resolved to %s for #%s', data.domain, exchange, data.id);
|
||||
|
||||
// Try to send the message
|
||||
this._process(exchange, data, (function(err, response) {
|
||||
if (err) {
|
||||
this._log('Failed processing message #%s', data.id);
|
||||
} else {
|
||||
this._log('Server responded for #%s: %s', data.id, JSON.stringify(response));
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if (err.responseCode && err.responseCode >= 500) {
|
||||
err.domain = data.domain;
|
||||
err.exchange = exchange;
|
||||
err.recipients = data.envelope.to;
|
||||
data.callback(err);
|
||||
} else {
|
||||
data.replies = (data.replies || 0) + 1;
|
||||
if (data.replies <= 5) {
|
||||
this._queue.insert(data, this._options.retryDelay || data.replies * 15 * 60 * 1000);
|
||||
this._log('Message #%s requeued', data.id);
|
||||
data.callback(null, {
|
||||
pending: {
|
||||
domain: data.domain,
|
||||
exchange: exchange,
|
||||
recipients: data.envelope.to,
|
||||
response: err.response
|
||||
}
|
||||
});
|
||||
} else {
|
||||
err.domain = data.domain;
|
||||
err.exchange = exchange;
|
||||
err.recipients = data.envelope.to;
|
||||
data.callback(err);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data.callback(null, response);
|
||||
}
|
||||
|
||||
setImmediate(this._loop.bind(this));
|
||||
}).bind(this));
|
||||
}).bind(this));
|
||||
}).bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends a message to provided MX server
|
||||
*
|
||||
* @param {String} exchange MX server
|
||||
* @param {Object} data Message object
|
||||
* @param {Function} callback Callback to run once the message is either sent or sending fails
|
||||
*/
|
||||
DirectMailer.prototype._process = function(exchange, data, callback) {
|
||||
this._log('Connecting to %s:%s for message #%s', exchange, this._options.port || 25, data.id);
|
||||
|
||||
var options = {
|
||||
host: exchange,
|
||||
port: this._options.port || 25,
|
||||
ignoreTLS: true
|
||||
};
|
||||
|
||||
// Add options from DirectMailer options to simplesmtp client
|
||||
Object.keys(this._options).forEach((function(key) {
|
||||
options[key] = this._options[key];
|
||||
}).bind(this));
|
||||
|
||||
var connection = new SMTPConnection(options);
|
||||
var returned = false;
|
||||
|
||||
connection.on('log', function(log) {
|
||||
this.emit('log', log);
|
||||
}.bind(this));
|
||||
|
||||
connection.once('error', function(err) {
|
||||
if (returned) {
|
||||
return;
|
||||
}
|
||||
returned = true;
|
||||
return callback(err);
|
||||
});
|
||||
|
||||
var sendMessage = function() {
|
||||
connection.send(data.envelope, data.message.createReadStream(), function(err, info) {
|
||||
if (returned) {
|
||||
return;
|
||||
}
|
||||
returned = true;
|
||||
|
||||
connection.close();
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
info.messageId = (data.message.getHeader('message-id') || '').replace(/[<>\s]/g, '');
|
||||
return callback(null, info);
|
||||
});
|
||||
};
|
||||
|
||||
connection.connect(function() {
|
||||
if (returned) {
|
||||
return;
|
||||
}
|
||||
sendMessage();
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds additional headers to the outgoing message
|
||||
*
|
||||
* @param {Object} message BuildMail message object
|
||||
*/
|
||||
DirectMailer.prototype._formatMessage = function(message) {
|
||||
var hostname = this._resolveHostname(this._options.name);
|
||||
|
||||
// set the first header as 'Received:'
|
||||
message._headers.unshift({
|
||||
key: 'Received',
|
||||
value: 'from localhost (127.0.0.1) by ' + hostname + ' with SMTP; ' + Date()
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Detects stream objects and resolves these to buffers before sending. File paths,
|
||||
* urls etc. are not affected.
|
||||
*
|
||||
* @param {Object} message BuildMail message object
|
||||
* @param {Function} callback Callback to run
|
||||
*/
|
||||
DirectMailer.prototype._clearStreams = function(mail, callback) {
|
||||
var streamNodes = [];
|
||||
|
||||
function walkNode(node) {
|
||||
if (node.content && typeof node.content.pipe === 'function') {
|
||||
streamNodes.push(node);
|
||||
}
|
||||
if (node.childNodes && node.childNodes.length) {
|
||||
node.childNodes.forEach(walkNode);
|
||||
}
|
||||
}
|
||||
walkNode(mail.message);
|
||||
|
||||
function resolveNodes() {
|
||||
if (!streamNodes.length) {
|
||||
return callback();
|
||||
}
|
||||
var node = streamNodes.shift();
|
||||
|
||||
mail.resolveContent(node, 'content', function(err) {
|
||||
if (err) {
|
||||
node.content = new Buffer('<' + err.message + '>');
|
||||
}
|
||||
setImmediate(resolveNodes);
|
||||
});
|
||||
}
|
||||
|
||||
resolveNodes();
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves MX server for a domain
|
||||
*
|
||||
* @param {String} domain Domain to resolve the MX to
|
||||
* @param {Function} callback Callback function to run
|
||||
*/
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Resolves current hostname. If resolved name is an IP address, uses 'localhost'.
|
||||
*
|
||||
* @param {String} [name] Preferred hostname
|
||||
* @return {String} Resolved hostname
|
||||
*/
|
||||
DirectMailer.prototype._resolveHostname = function(name) {
|
||||
if (!name || net.isIP(name.replace(/[\[\]]/g, '').trim())) {
|
||||
name = (os.hostname && os.hostname()) || '';
|
||||
}
|
||||
|
||||
if (!name || net.isIP(name.replace(/[\[\]]/g, '').trim())) {
|
||||
name = 'localhost';
|
||||
}
|
||||
|
||||
return name.toLowerCase();
|
||||
};
|
||||
118
node_modules/nodemailer-direct-transport/src/message-queue.js
generated
vendored
Normal file
118
node_modules/nodemailer-direct-transport/src/message-queue.js
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
'use strict';
|
||||
|
||||
// expose to the world
|
||||
module.exports = function() {
|
||||
return new MessageQueue();
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a queue object
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
function MessageQueue() {
|
||||
this._instantQueue = [];
|
||||
this._sortedQueue = [];
|
||||
this._shiftTimer = null;
|
||||
this._callbackQueue = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a callback to be run when something comes available from the queue
|
||||
*
|
||||
* @param {Function} callback Callback function to run with queue element as an argument
|
||||
*/
|
||||
MessageQueue.prototype.get = function(callback) {
|
||||
if (this._instantQueue.length) {
|
||||
callback(this._instantQueue.pop());
|
||||
} else {
|
||||
this._callbackQueue.unshift(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds an element to the queue. If delay (ms) is set, the data will not be available before
|
||||
* specified delay has passed. Otherwise the data will be available for processing immediatelly.
|
||||
*
|
||||
* @param {Mixed} data Value to be queued
|
||||
* @param {Number} [delay] If set, delay the availability of the data by {delay} milliseconds
|
||||
*/
|
||||
MessageQueue.prototype.insert = function(data, delay) {
|
||||
var container, added = -1;
|
||||
if (typeof delay !== 'number') {
|
||||
this._instantQueue.unshift(data);
|
||||
this._processInsert();
|
||||
return true;
|
||||
} else {
|
||||
container = {
|
||||
data: data,
|
||||
available: Date.now() + delay
|
||||
};
|
||||
for (var i = 0, len = this._sortedQueue.length; i < len; i++) {
|
||||
if (this._sortedQueue[i].available >= container.available) {
|
||||
this._sortedQueue.splice(i, 0, container);
|
||||
added = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (added < 0) {
|
||||
this._sortedQueue.push(container);
|
||||
added = 0;
|
||||
}
|
||||
|
||||
if (added === 0) {
|
||||
this._updateShiftTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears previous timer and creates a new one (if needed) to process the element
|
||||
* in the queue that needs to be processed first.
|
||||
*/
|
||||
MessageQueue.prototype._updateShiftTimer = function() {
|
||||
var nextShift, now = Date.now();
|
||||
clearTimeout(this._shiftTimer);
|
||||
|
||||
if (!this._sortedQueue.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
nextShift = this._sortedQueue[0].available;
|
||||
|
||||
if (nextShift <= now) {
|
||||
this._shiftSorted();
|
||||
} else {
|
||||
setTimeout(this._shiftSorted.bind(this),
|
||||
// add +15ms to ensure that data is already available when the timer is fired
|
||||
this._sortedQueue[0].available - Date.now() + 15);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Moves an element from the delayed queue to the immediate queue if an elmenet
|
||||
* becomes avilable
|
||||
*/
|
||||
MessageQueue.prototype._shiftSorted = function() {
|
||||
var container;
|
||||
if (!this._sortedQueue.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._sortedQueue[0].available <= Date.now()) {
|
||||
container = this._sortedQueue.shift();
|
||||
this.insert(container.data);
|
||||
}
|
||||
|
||||
this._updateShiftTimer();
|
||||
};
|
||||
|
||||
/**
|
||||
* If data from a queue is available and a callback is set, run the callback
|
||||
* with available data
|
||||
*/
|
||||
MessageQueue.prototype._processInsert = function() {
|
||||
if (this._instantQueue.length && this._callbackQueue.length) {
|
||||
this._callbackQueue.pop()(this._instantQueue.pop());
|
||||
}
|
||||
};
|
||||
202
node_modules/nodemailer-direct-transport/test/direct-transport-test.js
generated
vendored
Normal file
202
node_modules/nodemailer-direct-transport/test/direct-transport-test.js
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
'use strict';
|
||||
|
||||
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
||||
|
||||
var chai = require('chai');
|
||||
var expect = chai.expect;
|
||||
var directTransport = require('../src/direct-transport');
|
||||
var SMTPServer = require('smtp-server').SMTPServer;
|
||||
chai.config.includeStack = true;
|
||||
|
||||
var PORT_NUMBER = 8712;
|
||||
|
||||
function MockBuilder(envelope, message) {
|
||||
this.envelope = envelope;
|
||||
this.message = message;
|
||||
this._headers = [];
|
||||
}
|
||||
|
||||
MockBuilder.prototype.getEnvelope = function() {
|
||||
return this.envelope;
|
||||
};
|
||||
|
||||
MockBuilder.prototype.createReadStream = function() {
|
||||
return this.message;
|
||||
};
|
||||
|
||||
MockBuilder.prototype.getHeader = function() {
|
||||
return 'teretere';
|
||||
};
|
||||
|
||||
describe('SMTP Transport Tests', function() {
|
||||
this.timeout(100 * 1000);
|
||||
|
||||
var server;
|
||||
var retryCount = 0;
|
||||
|
||||
beforeEach(function(done) {
|
||||
server = new SMTPServer({
|
||||
disabledCommands: ['STARTTLS', 'AUTH'],
|
||||
|
||||
onData: function(stream, session, callback) {
|
||||
stream.on('data', function() {});
|
||||
stream.on('end', function() {
|
||||
var err;
|
||||
if (/retry@/.test(session.envelope.mailFrom.address) && retryCount++ < 3) {
|
||||
err = new Error('Please try again later');
|
||||
err.responseCode = 451;
|
||||
callback(err);
|
||||
} else {
|
||||
callback(null, 'OK');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onMailFrom: function(address, session, callback) {
|
||||
if (/invalid@/.test(address.address)) {
|
||||
return callback(new Error('Invalid sender'));
|
||||
}
|
||||
return callback(); // Accept the address
|
||||
},
|
||||
onRcptTo: function(address, session, callback) {
|
||||
if (/invalid@/.test(address.address)) {
|
||||
return callback(new Error('Invalid recipient'));
|
||||
}
|
||||
return callback(); // Accept the address
|
||||
},
|
||||
logger: false
|
||||
});
|
||||
|
||||
server.listen(PORT_NUMBER, done);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
server.close(done);
|
||||
});
|
||||
|
||||
it('Should expose version number', function() {
|
||||
var client = directTransport();
|
||||
expect(client.name).to.exist;
|
||||
expect(client.version).to.exist;
|
||||
});
|
||||
|
||||
it('Should send mail', function(done) {
|
||||
var client = directTransport({
|
||||
port: PORT_NUMBER,
|
||||
debug: false
|
||||
});
|
||||
|
||||
client.on('log', console.log);
|
||||
|
||||
var chunks = [],
|
||||
message = new Array(1024).join('teretere, vana kere\n');
|
||||
|
||||
server.on('data', function(connection, chunk) {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
server.on('dataReady', function(connection, callback) {
|
||||
var body = Buffer.concat(chunks);
|
||||
expect(body.toString()).to.equal(message.trim().replace(/\n/g, '\r\n'));
|
||||
callback(null, true);
|
||||
});
|
||||
|
||||
client.send({
|
||||
data: {},
|
||||
message: new MockBuilder({
|
||||
from: 'test@[127.0.0.1]',
|
||||
to: 'test@[127.0.0.1]'
|
||||
}, message)
|
||||
}, function(err, info) {
|
||||
expect(err).to.not.exist;
|
||||
expect(info.accepted).to.deep.equal(['test@[127.0.0.1]']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should retry mail', function(done) {
|
||||
var client = directTransport({
|
||||
port: PORT_NUMBER,
|
||||
debug: false,
|
||||
retryDelay: 1000
|
||||
});
|
||||
|
||||
client.on('log', console.log);
|
||||
|
||||
client.send({
|
||||
data: {},
|
||||
message: new MockBuilder({
|
||||
from: 'retry@[127.0.0.1]',
|
||||
to: ['test@[127.0.0.1]', 'test2@[127.0.0.1]']
|
||||
}, 'test')
|
||||
}, function(err, info) {
|
||||
expect(err).to.not.exist;
|
||||
expect(info.pending.length).to.equal(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should reject mail', function(done) {
|
||||
var client = directTransport({
|
||||
port: PORT_NUMBER,
|
||||
debug: false,
|
||||
retryDelay: 1000
|
||||
});
|
||||
|
||||
client.on('log', console.log);
|
||||
|
||||
client.send({
|
||||
data: {},
|
||||
message: new MockBuilder({
|
||||
from: 'invalid@[127.0.0.1]',
|
||||
to: ['test@[127.0.0.1]', 'test2@[127.0.0.1]']
|
||||
}, 'test')
|
||||
}, function(err) {
|
||||
expect(err).to.exist;
|
||||
expect(err.errors[0].recipients).to.deep.equal(['test@[127.0.0.1]', 'test2@[127.0.0.1]']);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should resolve MX', function(done) {
|
||||
var client = directTransport({
|
||||
port: PORT_NUMBER,
|
||||
debug: false,
|
||||
retryDelay: 1000
|
||||
});
|
||||
|
||||
client._resolveMx('kreata.ee', function(err, list) {
|
||||
expect(err).to.not.exist;
|
||||
expect(list.sort(function(a, b) {
|
||||
return a.priority - b.priority;
|
||||
})).to.deep.equal([{
|
||||
exchange: 'aspmx.l.google.com',
|
||||
priority: 10
|
||||
}, {
|
||||
exchange: 'alt1.aspmx.l.google.com',
|
||||
priority: 20
|
||||
}, {
|
||||
exchange: 'alt2.aspmx.l.google.com',
|
||||
priority: 30
|
||||
}]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('Should resolve A', function(done) {
|
||||
var client = directTransport({
|
||||
port: PORT_NUMBER,
|
||||
debug: false,
|
||||
retryDelay: 1000
|
||||
});
|
||||
|
||||
client._resolveMx('localhost.kreata.ee', function(err, list) {
|
||||
expect(err).to.not.exist;
|
||||
expect(list).to.deep.equal([{
|
||||
priority: 0,
|
||||
exchange: '127.0.0.1'
|
||||
}]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
56
node_modules/nodemailer-direct-transport/test/message-queue-test.js
generated
vendored
Normal file
56
node_modules/nodemailer-direct-transport/test/message-queue-test.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
'use strict';
|
||||
|
||||
var chai = require('chai');
|
||||
var expect = chai.expect;
|
||||
var createMessageQueue = require('../src/message-queue');
|
||||
chai.config.includeStack = true;
|
||||
|
||||
describe('Message Queue Tests', function() {
|
||||
var queue;
|
||||
|
||||
beforeEach(function() {
|
||||
queue = createMessageQueue();
|
||||
});
|
||||
|
||||
it('Should Add item to queue', function() {
|
||||
expect(queue._instantQueue).to.deep.equal([]);
|
||||
queue.insert('value1');
|
||||
expect(queue._instantQueue).to.deep.equal(['value1']);
|
||||
queue.insert('value2');
|
||||
expect(queue._instantQueue).to.deep.equal(['value2', 'value1']);
|
||||
});
|
||||
|
||||
it('Should Pull items from a queue', function(done) {
|
||||
queue.insert('value1');
|
||||
queue.insert('value2');
|
||||
|
||||
queue.get(function(value) {
|
||||
expect(value).to.be.equal('value1');
|
||||
|
||||
queue.get(function(value) {
|
||||
expect(value).to.be.equal('value2');
|
||||
expect(queue._instantQueue).to.deep.equal([]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('Should Add delayed items', function(done) {
|
||||
queue.insert('value1', 300);
|
||||
queue.insert('value2', 100);
|
||||
queue.insert('value3');
|
||||
|
||||
queue.get(function(value) {
|
||||
expect(value).to.be.equal('value3');
|
||||
|
||||
queue.get(function(value) {
|
||||
expect(value).to.be.equal('value2');
|
||||
|
||||
queue.get(function(value) {
|
||||
expect(value).to.be.equal('value1');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user