Added support for throttling
This commit is contained in:
parent
10bd4614ef
commit
cf0042c50a
9 changed files with 67 additions and 20 deletions
|
@ -116,7 +116,7 @@ function getTemplate(template, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMailer(callback) {
|
function createMailer(callback) {
|
||||||
settings.list(['smtpHostname', 'smtpPort', 'smtpEncryption', 'smtpUser', 'smtpPass', 'smtpLog', 'smtpDisableAuth', 'smtpMaxConnections', 'smtpMaxMessages', 'smtpSelfSigned', 'pgpPrivateKey', 'pgpPassphrase'], (err, configItems) => {
|
settings.list(['smtpHostname', 'smtpPort', 'smtpEncryption', 'smtpUser', 'smtpPass', 'smtpLog', 'smtpDisableAuth', 'smtpMaxConnections', 'smtpMaxMessages', 'smtpSelfSigned', 'pgpPrivateKey', 'pgpPassphrase', 'smtpThrottling'], (err, configItems) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return callback(err);
|
return callback(err);
|
||||||
}
|
}
|
||||||
|
@ -126,6 +126,7 @@ function createMailer(callback) {
|
||||||
oldListeners = module.exports.transport.listeners('idle');
|
oldListeners = module.exports.transport.listeners('idle');
|
||||||
module.exports.transport.removeAllListeners('idle');
|
module.exports.transport.removeAllListeners('idle');
|
||||||
module.exports.transport.removeAllListeners('stream');
|
module.exports.transport.removeAllListeners('stream');
|
||||||
|
module.exports.transport.checkThrottling = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.transport = nodemailer.createTransport({
|
module.exports.transport = nodemailer.createTransport({
|
||||||
|
@ -160,6 +161,27 @@ function createMailer(callback) {
|
||||||
oldListeners.forEach(listener => module.exports.transport.on('idle', listener));
|
oldListeners.forEach(listener => module.exports.transport.on('idle', listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let throttling = Number(configItems.smtpThrottling) || 0;
|
||||||
|
if (throttling) {
|
||||||
|
// convert to messages/second
|
||||||
|
throttling = 1 / (throttling / (3600 * 1000));
|
||||||
|
}
|
||||||
|
let lastCheck = Date.now();
|
||||||
|
module.exports.transport.checkThrottling = function (next) {
|
||||||
|
if (!throttling) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
let nextCheck = Date.now();
|
||||||
|
let checkDiff = (nextCheck - lastCheck);
|
||||||
|
lastCheck = nextCheck;
|
||||||
|
if (checkDiff < throttling) {
|
||||||
|
log.verbose('Mail', 'Throttling next message in %s sec.', (throttling - checkDiff) / 1000);
|
||||||
|
setTimeout(next, throttling - checkDiff);
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
caches.cache.delete('sender queue');
|
caches.cache.delete('sender queue');
|
||||||
return callback(null, module.exports.transport);
|
return callback(null, module.exports.transport);
|
||||||
});
|
});
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
"grunt": "^1.0.1",
|
"grunt": "^1.0.1",
|
||||||
"grunt-cli": "^1.2.0",
|
"grunt-cli": "^1.2.0",
|
||||||
"grunt-contrib-nodeunit": "^1.0.0",
|
"grunt-contrib-nodeunit": "^1.0.0",
|
||||||
"grunt-eslint": "^18.1.0"
|
"grunt-eslint": "^19.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt-nodejs": "0.0.3",
|
"bcrypt-nodejs": "0.0.3",
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
"csv-parse": "^1.1.1",
|
"csv-parse": "^1.1.1",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"express": "^4.14.0",
|
"express": "^4.14.0",
|
||||||
"express-session": "^1.13.0",
|
"express-session": "^1.14.0",
|
||||||
"faker": "^3.1.0",
|
"faker": "^3.1.0",
|
||||||
"feedparser": "^1.1.4",
|
"feedparser": "^1.1.4",
|
||||||
"geoip-ultralight": "^0.1.4",
|
"geoip-ultralight": "^0.1.4",
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
"humanize": "0.0.9",
|
"humanize": "0.0.9",
|
||||||
"is-url": "^1.2.1",
|
"is-url": "^1.2.1",
|
||||||
"isemail": "^2.2.0",
|
"isemail": "^2.2.0",
|
||||||
"jsdom": "^9.3.0",
|
"jsdom": "^9.4.0",
|
||||||
"juice": "^2.0.0",
|
"juice": "^2.0.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"moment-timezone": "^0.5.4",
|
"moment-timezone": "^0.5.4",
|
||||||
|
|
|
@ -12,6 +12,7 @@ $('.summernote').summernote({
|
||||||
$('div.code-editor').each(function () {
|
$('div.code-editor').each(function () {
|
||||||
var editor = ace.edit(this);
|
var editor = ace.edit(this);
|
||||||
var textarea = document.querySelector('input[name=html]');
|
var textarea = document.querySelector('input[name=html]');
|
||||||
|
|
||||||
editor.setTheme('ace/theme/chrome');
|
editor.setTheme('ace/theme/chrome');
|
||||||
editor.getSession().setMode('ace/mode/html');
|
editor.getSession().setMode('ace/mode/html');
|
||||||
editor.getSession().setUseWrapMode(true);
|
editor.getSession().setUseWrapMode(true);
|
||||||
|
|
|
@ -11,7 +11,7 @@ let url = require('url');
|
||||||
|
|
||||||
let settings = require('../lib/models/settings');
|
let settings = require('../lib/models/settings');
|
||||||
|
|
||||||
let allowedKeys = ['service_url', 'smtp_hostname', 'smtp_port', 'smtp_encryption', 'smtp_disable_auth', 'smtp_user', 'smtp_pass', 'admin_email', 'smtp_log', 'smtp_max_connections', 'smtp_max_messages', 'smtp_self_signed', 'default_from', 'default_address', 'default_subject', 'default_homepage', 'default_postaddress', 'default_sender', 'verp_hostname', 'verp_use', 'disable_wysiwyg', 'pgp_private_key', 'pgp_passphrase', 'ua_code', 'shoutout', 'disable_confirmations'];
|
let allowedKeys = ['service_url', 'smtp_hostname', 'smtp_port', 'smtp_encryption', 'smtp_disable_auth', 'smtp_user', 'smtp_pass', 'admin_email', 'smtp_log', 'smtp_max_connections', 'smtp_max_messages', 'smtp_self_signed', 'default_from', 'default_address', 'default_subject', 'default_homepage', 'default_postaddress', 'default_sender', 'verp_hostname', 'verp_use', 'disable_wysiwyg', 'pgp_private_key', 'pgp_passphrase', 'ua_code', 'shoutout', 'disable_confirmations', 'smtp_throttling'];
|
||||||
|
|
||||||
router.all('/*', (req, res, next) => {
|
router.all('/*', (req, res, next) => {
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
|
|
|
@ -65,6 +65,7 @@ router.get('/create', passport.csrfProtection, (req, res, next) => {
|
||||||
data.html = data.html || rendererHtml(configItems);
|
data.html = data.html || rendererHtml(configItems);
|
||||||
data.text = data.text || rendererText(configItems);
|
data.text = data.text || rendererText(configItems);
|
||||||
data.disableWysiwyg = configItems.disableWysiwyg;
|
data.disableWysiwyg = configItems.disableWysiwyg;
|
||||||
|
|
||||||
res.render('templates/create', data);
|
res.render('templates/create', data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -430,12 +430,12 @@ let sendLoop = () => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
setImmediate(trySend);
|
setImmediate(trySend);
|
||||||
setImmediate(getNext);
|
setImmediate(() => mailer.transport.checkThrottling(getNext));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
mailer.transport.on('idle', getNext);
|
mailer.transport.on('idle', () => mailer.transport.checkThrottling(getNext));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -194,6 +194,16 @@
|
||||||
Advanced SMTP settings
|
Advanced SMTP settings
|
||||||
</legend>
|
</legend>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-offset-2 col-xs-4">
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="smtp-log" {{#if smtpLog}} checked {{/if}}> Log SMTP transactions
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-xs-4">
|
<div class="col-sm-offset-2 col-xs-4">
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
@ -206,27 +216,25 @@
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="smtp-max-connections" class="col-sm-2 control-label">Max connections</label>
|
<label for="smtp-max-connections" class="col-sm-2 control-label">Max connections</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-6">
|
||||||
<input type="number" class="form-control" name="smtp-max-connections" id="smtp-port" placeholder="The count of max connections, eg. 10" value="{{smtpMaxConnections}}">
|
<input type="number" class="form-control" name="smtp-max-connections" id="smtp-max-connections" placeholder="The count of max connections, eg. 10" value="{{smtpMaxConnections}}">
|
||||||
<span class="help-block">The count of maximum simultaneous connections to make against the SMTP server (defaults to 5)</span>
|
<span class="help-block">The count of maximum simultaneous connections to make against the SMTP server (defaults to 5)</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="smtp-max-messages" class="col-sm-2 control-label">Max messages</label>
|
<label for="smtp-max-messages" class="col-sm-2 control-label">Max messages</label>
|
||||||
<div class="col-sm-4">
|
<div class="col-sm-6">
|
||||||
<input type="number" class="form-control" name="smtp-max-messages" id="smtp-port" placeholder="The count of max messages, eg. 100" value="{{smtpMaxMessages}}">
|
<input type="number" class="form-control" name="smtp-max-messages" id="smtp-max-messages" placeholder="The count of max messages, eg. 100" value="{{smtpMaxMessages}}">
|
||||||
<span class="help-block">The count of messages to send through a single connection before the connection is recreated (defaults to 100)</span>
|
<span class="help-block">The number of messages to send through a single connection before the connection is closed and reopened (defaults to 100)</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="col-sm-offset-2 col-xs-4">
|
<label for="smtp-throttling" class="col-sm-2 control-label">Throttling</label>
|
||||||
<div class="checkbox">
|
<div class="col-sm-6">
|
||||||
<label>
|
<input type="number" class="form-control" name="smtp-throttling" id="smtp-throttling" placeholder="Messages per hour eg. 1000" value="{{smtpThrottling}}">
|
||||||
<input type="checkbox" name="smtp-log" {{#if smtpLog}} checked {{/if}}> Log SMTP transactions
|
<span class="help-block">Maximum number of messages to send in an hour. Leave empty or zero for no throttling. If your provider uses a different speed limit (<em>messages/minute</em> or <em>messages/second</em>) then convert this limit into <em>messages/hour</em> (1m/s => 3600m/h).</span>
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
<div class="col-sm-offset-2 col-sm-10">
|
<div class="col-sm-offset-2 col-sm-10">
|
||||||
<a class="btn btn-default" role="button" data-toggle="collapse" href="#mergeReference" aria-expanded="false" aria-controls="mergeReference">Merge tag reference</a>
|
<a class="btn btn-default" role="button" data-toggle="collapse" href="#mergeReference" aria-expanded="false" aria-controls="mergeReference">Merge tag reference</a>
|
||||||
<div class="collapse" id="mergeReference">
|
<div class="collapse" id="mergeReference">
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Merge tags are tags that are replaced before sending out the message. The format of the merge tag is the following: <code>[TAG_NAME]</code> or <code>[TAG_NAME/fallback]</code> where <code>fallback</code> is an optional text value used
|
Merge tags are tags that are replaced before sending out the message. The format of the merge tag is the following: <code>[TAG_NAME]</code> or <code>[TAG_NAME/fallback]</code> where <code>fallback</code> is an optional text value used
|
||||||
when <code>TAG_NAME</code> is empty.
|
when <code>TAG_NAME</code> is empty.
|
||||||
|
@ -69,12 +70,14 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
|
||||||
{{#if disableWysiwyg}}
|
{{#if disableWysiwyg}}
|
||||||
<div class="code-editor" id="template-html">{{html}}</div>
|
<div class="code-editor" id="template-html">{{html}}</div>
|
||||||
<input type="hidden" name="html">
|
<input type="hidden" name="html">
|
||||||
{{else}}
|
{{else}}
|
||||||
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,9 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>
|
||||||
|
<code>[EMAIL]</code> – email address of the subscriber
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<code>[FIRST_NAME]</code> – first name of the subscriber
|
<code>[FIRST_NAME]</code> – first name of the subscriber
|
||||||
</li>
|
</li>
|
||||||
|
@ -52,6 +55,15 @@
|
||||||
<li>
|
<li>
|
||||||
<code>[LINK_BROWSER]</code> – URL to preview the message in a browser
|
<code>[LINK_BROWSER]</code> – URL to preview the message in a browser
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>[SUBSCRIPTION_ID]</code> – Unique ID that identifies the recipient
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>[LIST_ID]</code> – Unique ID that identifies the list used for this campaign
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<code>[CAMPAIGN_ID]</code> – Unique ID that identifies current campaign
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>
|
<p>
|
||||||
In addition to that any custom field can have its own merge tag.
|
In addition to that any custom field can have its own merge tag.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue