mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-03 11:01:20 +01:00
feat: closes #13009, add dedicated test smtp button
which uses the dirty settings on the page add clarification under send test email button add missing lang keys
This commit is contained in:
@@ -30,14 +30,20 @@
|
|||||||
"smtp-transport.pool-help": "Pooling connections prevents NodeBB from creating a new connection for every email. This option only applies if SMTP Transport is enabled.",
|
"smtp-transport.pool-help": "Pooling connections prevents NodeBB from creating a new connection for every email. This option only applies if SMTP Transport is enabled.",
|
||||||
"smtp-transport.allow-self-signed": "Allow self-signed certificates",
|
"smtp-transport.allow-self-signed": "Allow self-signed certificates",
|
||||||
"smtp-transport.allow-self-signed-help": "Enabling this setting will allow you to use self-signed or invalid TLS certificates.",
|
"smtp-transport.allow-self-signed-help": "Enabling this setting will allow you to use self-signed or invalid TLS certificates.",
|
||||||
|
"smtp-transport.test-success": "SMTP Test email sent successfully.",
|
||||||
|
|
||||||
"template": "Edit Email Template",
|
"template": "Edit Email Template",
|
||||||
"template.select": "Select Email Template",
|
"template.select": "Select Email Template",
|
||||||
"template.revert": "Revert to Original",
|
"template.revert": "Revert to Original",
|
||||||
|
"test-smtp-settings": "Test SMTP Settings",
|
||||||
"testing": "Email Testing",
|
"testing": "Email Testing",
|
||||||
|
"testing.success": "Test Email Sent.",
|
||||||
"testing.select": "Select Email Template",
|
"testing.select": "Select Email Template",
|
||||||
"testing.send": "Send Test Email",
|
"testing.send": "Send Test Email",
|
||||||
"testing.send-help": "The test email will be sent to the currently logged in user's email address.",
|
"testing.send-help-plugin": "<strong>\"%1\"</strong> will be used to send test emails.",
|
||||||
|
"testing.send-help-smtp": "SMTP transport is enabled and will be used to send emails.",
|
||||||
|
"testing.send-help-no-plugin": "No emailer plugin is installed to send emails, nodemailer will be used by default.",
|
||||||
|
"testing.send-help": "The test email will be sent to the currently logged in user's email address using the saved settings on this page. ",
|
||||||
"subscriptions": "Email Digests",
|
"subscriptions": "Email Digests",
|
||||||
"subscriptions.disable": "Disable email digests",
|
"subscriptions.disable": "Disable email digests",
|
||||||
"subscriptions.hour": "Digest Hour",
|
"subscriptions.hour": "Digest Hour",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ define('admin/settings/email', ['ace/ace', 'alerts', 'admin/settings'], function
|
|||||||
let emailEditor;
|
let emailEditor;
|
||||||
|
|
||||||
module.init = function () {
|
module.init = function () {
|
||||||
|
configureSmtpTester();
|
||||||
configureEmailTester();
|
configureEmailTester();
|
||||||
configureEmailEditor();
|
configureEmailEditor();
|
||||||
handleDigestHourChange();
|
handleDigestHourChange();
|
||||||
@@ -26,6 +27,29 @@ define('admin/settings/email', ['ace/ace', 'alerts', 'admin/settings'], function
|
|||||||
socket.emit('admin.user.restartJobs');
|
socket.emit('admin.user.restartJobs');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function configureSmtpTester() {
|
||||||
|
$('[data-action="email.smtp.test"]').on('click', function () {
|
||||||
|
const smtpOptions = {};
|
||||||
|
$('[data-field^="email:smtp"]').each(function (index, el) {
|
||||||
|
const $el = $(el);
|
||||||
|
const key = $el.attr('data-field');
|
||||||
|
if ($el.is(':checkbox')) {
|
||||||
|
smtpOptions[key] = $el.is(':checked');
|
||||||
|
} else {
|
||||||
|
smtpOptions[key] = $el.val();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
socket.emit('admin.email.testSmtp', { smtp: smtpOptions }, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error(err.message);
|
||||||
|
return alerts.error(err);
|
||||||
|
}
|
||||||
|
alerts.success('[[admin/settings/email:smtp-transport.test-success]]');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function configureEmailTester() {
|
function configureEmailTester() {
|
||||||
$('button[data-action="email.test"]').off('click').on('click', function () {
|
$('button[data-action="email.test"]').off('click').on('click', function () {
|
||||||
socket.emit('admin.email.test', { template: $('#test-email').val() }, function (err) {
|
socket.emit('admin.email.test', { template: $('#test-email').val() }, function (err) {
|
||||||
@@ -33,7 +57,7 @@ define('admin/settings/email', ['ace/ace', 'alerts', 'admin/settings'], function
|
|||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
return alerts.error(err);
|
return alerts.error(err);
|
||||||
}
|
}
|
||||||
alerts.success('Test Email Sent');
|
alerts.success('[[admin/settings/email:testing.success]]');
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ const api = require('../../api');
|
|||||||
const pagination = require('../../pagination');
|
const pagination = require('../../pagination');
|
||||||
const helpers = require('../helpers');
|
const helpers = require('../helpers');
|
||||||
const translator = require('../../translator');
|
const translator = require('../../translator');
|
||||||
|
const plugins = require('../../plugins');
|
||||||
|
|
||||||
const settingsController = module.exports;
|
const settingsController = module.exports;
|
||||||
|
|
||||||
@@ -114,9 +115,14 @@ settingsController.uploads = async (req, res) => {
|
|||||||
|
|
||||||
settingsController.email = async (req, res) => {
|
settingsController.email = async (req, res) => {
|
||||||
const emails = await emailer.getTemplates(meta.config);
|
const emails = await emailer.getTemplates(meta.config);
|
||||||
|
const hooks = plugins.loadedHooks['static:email.send'];
|
||||||
|
const emailerPlugin = hooks && hooks.length ? hooks[0].id : null;
|
||||||
|
const smtpEnabled = parseInt(meta.config['email:smtpTransport:enabled'], 10) === 1;
|
||||||
|
|
||||||
res.render('admin/settings/email', {
|
res.render('admin/settings/email', {
|
||||||
title: '[[admin/menu:settings/email]]',
|
title: '[[admin/menu:settings/email]]',
|
||||||
|
emailerPlugin,
|
||||||
|
smtpEnabled,
|
||||||
emails: emails,
|
emails: emails,
|
||||||
sendable: emails.filter(e => !e.path.includes('_plaintext') && !e.path.includes('partials')).map(tpl => tpl.path),
|
sendable: emails.filter(e => !e.path.includes('_plaintext') && !e.path.includes('partials')).map(tpl => tpl.path),
|
||||||
services: emailer.listServices(),
|
services: emailer.listServices(),
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ const smtpSettingsChanged = (config) => {
|
|||||||
|
|
||||||
const getHostname = () => {
|
const getHostname = () => {
|
||||||
const configUrl = nconf.get('url');
|
const configUrl = nconf.get('url');
|
||||||
const parsed = url.parse(configUrl);
|
return new URL(configUrl).hostname;
|
||||||
return parsed.hostname;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const buildCustomTemplates = async (config) => {
|
const buildCustomTemplates = async (config) => {
|
||||||
@@ -120,51 +119,55 @@ Emailer.setupFallbackTransport = (config) => {
|
|||||||
winston.verbose('[emailer] Setting up fallback transport');
|
winston.verbose('[emailer] Setting up fallback transport');
|
||||||
// Enable SMTP transport if enabled in ACP
|
// Enable SMTP transport if enabled in ACP
|
||||||
if (parseInt(config['email:smtpTransport:enabled'], 10) === 1) {
|
if (parseInt(config['email:smtpTransport:enabled'], 10) === 1) {
|
||||||
const smtpOptions = {
|
Emailer.transports.smtp = Emailer.createSmtpTransport(config);
|
||||||
name: getHostname(),
|
|
||||||
pool: config['email:smtpTransport:pool'],
|
|
||||||
};
|
|
||||||
|
|
||||||
if (config['email:smtpTransport:user'] || config['email:smtpTransport:pass']) {
|
|
||||||
smtpOptions.auth = {
|
|
||||||
user: config['email:smtpTransport:user'],
|
|
||||||
pass: config['email:smtpTransport:pass'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config['email:smtpTransport:service'] === 'nodebb-custom-smtp') {
|
|
||||||
smtpOptions.port = config['email:smtpTransport:port'];
|
|
||||||
smtpOptions.host = config['email:smtpTransport:host'];
|
|
||||||
|
|
||||||
if (config['email:smtpTransport:security'] === 'NONE') {
|
|
||||||
smtpOptions.secure = false;
|
|
||||||
smtpOptions.requireTLS = false;
|
|
||||||
smtpOptions.ignoreTLS = true;
|
|
||||||
} else if (config['email:smtpTransport:security'] === 'STARTTLS') {
|
|
||||||
smtpOptions.secure = false;
|
|
||||||
smtpOptions.requireTLS = true;
|
|
||||||
smtpOptions.ignoreTLS = false;
|
|
||||||
} else {
|
|
||||||
// meta.config['email:smtpTransport:security'] === 'ENCRYPTED' or undefined
|
|
||||||
smtpOptions.secure = true;
|
|
||||||
smtpOptions.requireTLS = true;
|
|
||||||
smtpOptions.ignoreTLS = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
smtpOptions.service = String(config['email:smtpTransport:service']);
|
|
||||||
}
|
|
||||||
if (config['email:smtpTransport:allow-self-signed']) {
|
|
||||||
smtpOptions.tls = {
|
|
||||||
rejectUnauthorized: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Emailer.transports.smtp = nodemailer.createTransport(smtpOptions);
|
|
||||||
Emailer.fallbackTransport = Emailer.transports.smtp;
|
Emailer.fallbackTransport = Emailer.transports.smtp;
|
||||||
} else {
|
} else {
|
||||||
Emailer.fallbackTransport = Emailer.transports.sendmail;
|
Emailer.fallbackTransport = Emailer.transports.sendmail;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Emailer.createSmtpTransport = (config) => {
|
||||||
|
const smtpOptions = {
|
||||||
|
name: getHostname(),
|
||||||
|
pool: config['email:smtpTransport:pool'],
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config['email:smtpTransport:user'] || config['email:smtpTransport:pass']) {
|
||||||
|
smtpOptions.auth = {
|
||||||
|
user: config['email:smtpTransport:user'],
|
||||||
|
pass: config['email:smtpTransport:pass'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config['email:smtpTransport:service'] === 'nodebb-custom-smtp') {
|
||||||
|
smtpOptions.port = config['email:smtpTransport:port'];
|
||||||
|
smtpOptions.host = config['email:smtpTransport:host'];
|
||||||
|
|
||||||
|
if (config['email:smtpTransport:security'] === 'NONE') {
|
||||||
|
smtpOptions.secure = false;
|
||||||
|
smtpOptions.requireTLS = false;
|
||||||
|
smtpOptions.ignoreTLS = true;
|
||||||
|
} else if (config['email:smtpTransport:security'] === 'STARTTLS') {
|
||||||
|
smtpOptions.secure = false;
|
||||||
|
smtpOptions.requireTLS = true;
|
||||||
|
smtpOptions.ignoreTLS = false;
|
||||||
|
} else {
|
||||||
|
// meta.config['email:smtpTransport:security'] === 'ENCRYPTED' or undefined
|
||||||
|
smtpOptions.secure = true;
|
||||||
|
smtpOptions.requireTLS = true;
|
||||||
|
smtpOptions.ignoreTLS = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
smtpOptions.service = String(config['email:smtpTransport:service']);
|
||||||
|
}
|
||||||
|
if (config['email:smtpTransport:allow-self-signed']) {
|
||||||
|
smtpOptions.tls = {
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return nodemailer.createTransport(smtpOptions);
|
||||||
|
};
|
||||||
|
|
||||||
Emailer.registerApp = (expressApp) => {
|
Emailer.registerApp = (expressApp) => {
|
||||||
app = expressApp;
|
app = expressApp;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const nconf = require('nconf');
|
||||||
const winston = require('winston');
|
const winston = require('winston');
|
||||||
|
|
||||||
const meta = require('../../meta');
|
const meta = require('../../meta');
|
||||||
@@ -8,6 +9,7 @@ const userEmail = require('../../user/email');
|
|||||||
const notifications = require('../../notifications');
|
const notifications = require('../../notifications');
|
||||||
const emailer = require('../../emailer');
|
const emailer = require('../../emailer');
|
||||||
const utils = require('../../utils');
|
const utils = require('../../utils');
|
||||||
|
const user = require('../../user');
|
||||||
|
|
||||||
const Email = module.exports;
|
const Email = module.exports;
|
||||||
|
|
||||||
@@ -72,3 +74,25 @@ Email.test = async function (socket, data) {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Email.testSmtp = async (socket, data) => {
|
||||||
|
try {
|
||||||
|
const smtp = emailer.createSmtpTransport(data.smtp);
|
||||||
|
const content = 'This is a test email sent from NodeBB to verify your SMTP settings are correct.';
|
||||||
|
const { hostname } = new URL(nconf.get('url'));
|
||||||
|
const toEmail = await user.getUserField(socket.uid, 'email');
|
||||||
|
await smtp.sendMail({
|
||||||
|
to: toEmail,
|
||||||
|
subject: `[${meta.config.title}] SMTP Settings Test Email`,
|
||||||
|
html: content,
|
||||||
|
text: content,
|
||||||
|
from: {
|
||||||
|
name: meta.config['email:from_name'] || 'NodeBB',
|
||||||
|
address: meta.config['email:from'] || `no-reply@${hostname}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
winston.error(err.stack);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -167,10 +167,13 @@
|
|||||||
[[admin/settings/email:smtp-transport.username-help]]
|
[[admin/settings/email:smtp-transport.username-help]]
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="mb-3">
|
||||||
<label class="form-label" for="email:smtpTransport:pass">[[admin/settings/email:smtp-transport.password]]</label>
|
<label class="form-label" for="email:smtpTransport:pass">[[admin/settings/email:smtp-transport.password]]</label>
|
||||||
<input id="email:smtpTransport:pass" type="password" class="form-control input-lg" data-field="email:smtpTransport:pass" autocomplete="off" />
|
<input id="email:smtpTransport:pass" type="password" class="form-control input-lg" data-field="email:smtpTransport:pass" autocomplete="off" />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-primary text-nowrap" type="button" data-action="email.smtp.test">[[admin/settings/email:test-smtp-settings]]</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="email-testing" class="mb-4">
|
<div id="email-testing" class="mb-4">
|
||||||
@@ -181,14 +184,23 @@
|
|||||||
<div class="d-flex justify-content-between gap-1">
|
<div class="d-flex justify-content-between gap-1">
|
||||||
<select id="test-email" class="form-select">
|
<select id="test-email" class="form-select">
|
||||||
{{{ each sendable }}}
|
{{{ each sendable }}}
|
||||||
<option value="{@value}">{@value}</option>
|
<option value="{@value}" {{{ if (@value == "test")}}} selected{{{ end }}}>{@value}</option>
|
||||||
{{{ end }}}
|
{{{ end }}}
|
||||||
</select>
|
</select>
|
||||||
<button class="btn btn-primary text-nowrap" type="button" data-action="email.test">[[admin/settings/email:testing.send]]</button>
|
<button class="btn btn-primary text-nowrap" type="button" data-action="email.test">[[admin/settings/email:testing.send]]</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class="form-text">
|
<p class="form-text">
|
||||||
[[admin/settings/email:testing.send-help]]
|
[[admin/settings/email:testing.send-help]]<br/>
|
||||||
|
{{{ if emailerPlugin }}}
|
||||||
|
[[admin/settings/email:testing.send-help-plugin, {emailerPlugin}]]
|
||||||
|
{{{ else }}}
|
||||||
|
{{{ if smtpEnabled }}}
|
||||||
|
[[admin/settings/email:testing.send-help-smtp]]
|
||||||
|
{{{ else }}}
|
||||||
|
[[admin/settings/email:testing.send-help-no-plugin]]
|
||||||
|
{{{ end }}}
|
||||||
|
{{{ end }}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user