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) {
|
||||
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) {
|
||||
return callback(err);
|
||||
}
|
||||
|
@ -126,6 +126,7 @@ function createMailer(callback) {
|
|||
oldListeners = module.exports.transport.listeners('idle');
|
||||
module.exports.transport.removeAllListeners('idle');
|
||||
module.exports.transport.removeAllListeners('stream');
|
||||
module.exports.transport.checkThrottling = null;
|
||||
}
|
||||
|
||||
module.exports.transport = nodemailer.createTransport({
|
||||
|
@ -160,6 +161,27 @@ function createMailer(callback) {
|
|||
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');
|
||||
return callback(null, module.exports.transport);
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"grunt": "^1.0.1",
|
||||
"grunt-cli": "^1.2.0",
|
||||
"grunt-contrib-nodeunit": "^1.0.0",
|
||||
"grunt-eslint": "^18.1.0"
|
||||
"grunt-eslint": "^19.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"bcrypt-nodejs": "0.0.3",
|
||||
|
@ -41,7 +41,7 @@
|
|||
"csv-parse": "^1.1.1",
|
||||
"escape-html": "^1.0.3",
|
||||
"express": "^4.14.0",
|
||||
"express-session": "^1.13.0",
|
||||
"express-session": "^1.14.0",
|
||||
"faker": "^3.1.0",
|
||||
"feedparser": "^1.1.4",
|
||||
"geoip-ultralight": "^0.1.4",
|
||||
|
@ -52,7 +52,7 @@
|
|||
"humanize": "0.0.9",
|
||||
"is-url": "^1.2.1",
|
||||
"isemail": "^2.2.0",
|
||||
"jsdom": "^9.3.0",
|
||||
"jsdom": "^9.4.0",
|
||||
"juice": "^2.0.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"moment-timezone": "^0.5.4",
|
||||
|
|
|
@ -12,6 +12,7 @@ $('.summernote').summernote({
|
|||
$('div.code-editor').each(function () {
|
||||
var editor = ace.edit(this);
|
||||
var textarea = document.querySelector('input[name=html]');
|
||||
|
||||
editor.setTheme('ace/theme/chrome');
|
||||
editor.getSession().setMode('ace/mode/html');
|
||||
editor.getSession().setUseWrapMode(true);
|
||||
|
|
|
@ -11,7 +11,7 @@ let url = require('url');
|
|||
|
||||
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) => {
|
||||
if (!req.user) {
|
||||
|
|
|
@ -65,6 +65,7 @@ router.get('/create', passport.csrfProtection, (req, res, next) => {
|
|||
data.html = data.html || rendererHtml(configItems);
|
||||
data.text = data.text || rendererText(configItems);
|
||||
data.disableWysiwyg = configItems.disableWysiwyg;
|
||||
|
||||
res.render('templates/create', data);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -430,12 +430,12 @@ let sendLoop = () => {
|
|||
});
|
||||
};
|
||||
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
|
||||
</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="col-sm-offset-2 col-xs-4">
|
||||
<div class="checkbox">
|
||||
|
@ -206,27 +216,25 @@
|
|||
|
||||
<div class="form-group">
|
||||
<label for="smtp-max-connections" class="col-sm-2 control-label">Max connections</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="number" class="form-control" name="smtp-max-connections" id="smtp-port" placeholder="The count of max connections, eg. 10" value="{{smtpMaxConnections}}">
|
||||
<div class="col-sm-6">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="smtp-max-messages" class="col-sm-2 control-label">Max messages</label>
|
||||
<div class="col-sm-4">
|
||||
<input type="number" class="form-control" name="smtp-max-messages" id="smtp-port" 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>
|
||||
<div class="col-sm-6">
|
||||
<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 number of messages to send through a single connection before the connection is closed and reopened (defaults to 100)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<label for="smtp-throttling" class="col-sm-2 control-label">Throttling</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="number" class="form-control" name="smtp-throttling" id="smtp-throttling" placeholder="Messages per hour eg. 1000" value="{{smtpThrottling}}">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<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>
|
||||
<div class="collapse" id="mergeReference">
|
||||
|
||||
<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
|
||||
when <code>TAG_NAME</code> is empty.
|
||||
|
@ -69,12 +70,14 @@
|
|||
<div class="form-group">
|
||||
<label for="template-html" class="col-sm-2 control-label">Template content (HTML)</label>
|
||||
<div class="col-sm-10">
|
||||
|
||||
{{#if disableWysiwyg}}
|
||||
<div class="code-editor" id="template-html">{{html}}</div>
|
||||
<input type="hidden" name="html">
|
||||
{{else}}
|
||||
<textarea class="form-control summernote" id="template-html" name="html" rows="8">{{html}}</textarea>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
</p>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<code>[EMAIL]</code> – email address of the subscriber
|
||||
</li>
|
||||
<li>
|
||||
<code>[FIRST_NAME]</code> – first name of the subscriber
|
||||
</li>
|
||||
|
@ -52,6 +55,15 @@
|
|||
<li>
|
||||
<code>[LINK_BROWSER]</code> – URL to preview the message in a browser
|
||||
</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>
|
||||
<p>
|
||||
In addition to that any custom field can have its own merge tag.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue