mirror of
https://github.com/nodemailer/wildduck.git
synced 2025-09-11 07:34:48 +08:00
fix(outbound-mta-relay): ZMS-171 Add support for an outbound MTA relay (#787)
* add support for an outbound MTA relay * add mtaRelay logic to all necessary parts
This commit is contained in:
parent
1f4fc20950
commit
77625e89d7
8 changed files with 108 additions and 16 deletions
|
@ -2634,6 +2634,7 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
let message = result.value.message;
|
||||
|
||||
let messageData;
|
||||
let userData;
|
||||
try {
|
||||
messageData = await db.database.collection('messages').findOne(
|
||||
{
|
||||
|
@ -2653,6 +2654,18 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
}
|
||||
}
|
||||
);
|
||||
|
||||
userData = await db.database.collection('users').findOne(
|
||||
{
|
||||
_id: user
|
||||
},
|
||||
{
|
||||
projection: {
|
||||
_id: true,
|
||||
mtaRelay: true
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
res.status(500);
|
||||
return res.json({
|
||||
|
@ -2705,7 +2718,8 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
sender: messageData.meta.from,
|
||||
recipient: messageData.meta.to,
|
||||
targets: forwardTargets,
|
||||
stream: response.value
|
||||
stream: response.value,
|
||||
userData
|
||||
};
|
||||
|
||||
let queueId;
|
||||
|
@ -3983,7 +3997,8 @@ module.exports = (db, server, messageHandler, userHandler, storageHandler, setti
|
|||
to: envelope.to,
|
||||
sendTime,
|
||||
origin: options.origin || options.ip,
|
||||
runPlugins: true
|
||||
runPlugins: true,
|
||||
mtaRelay: userData.mtaRelay || false
|
||||
},
|
||||
(err, ...args) => {
|
||||
if (err || !args[0]) {
|
||||
|
|
|
@ -58,7 +58,8 @@ module.exports = (db, server, messageHandler, userHandler, settingsHandler) => {
|
|||
pubKey: true,
|
||||
disabled: true,
|
||||
suspended: true,
|
||||
fromWhitelist: true
|
||||
fromWhitelist: true,
|
||||
mtaRelay: true
|
||||
}
|
||||
},
|
||||
(err, userData) => {
|
||||
|
@ -473,7 +474,8 @@ module.exports = (db, server, messageHandler, userHandler, settingsHandler) => {
|
|||
to: compiledEnvelope.to,
|
||||
sendTime,
|
||||
origin: options.ip,
|
||||
runPlugins: true
|
||||
runPlugins: true,
|
||||
mtaRelay: userData.mtaRelay || false
|
||||
},
|
||||
(err, ...args) => {
|
||||
if (err || !args[0]) {
|
||||
|
|
|
@ -352,6 +352,14 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
'An array of forwarding targets. The value could either be an email address or a relay url to next MX server ("smtp://mx2.zone.eu:25") or an URL where mail contents are POSTed to'
|
||||
),
|
||||
|
||||
mtaRelay: Joi.string()
|
||||
.uri({
|
||||
scheme: [/smtps?/],
|
||||
allowRelative: false,
|
||||
relativeOnly: false
|
||||
})
|
||||
.description('An address of an SMTP MTA relay. The value should be a relay url. If specified uses the this relay as the outbound MTA.'),
|
||||
|
||||
spamLevel: Joi.number()
|
||||
.min(0)
|
||||
.max(100)
|
||||
|
@ -500,6 +508,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
let values = permission.filter(result.value);
|
||||
|
||||
let targets = values.targets;
|
||||
let mtaRelay = values.mtaRelay;
|
||||
|
||||
if (targets) {
|
||||
for (let i = 0, len = targets.length; i < len; i++) {
|
||||
|
@ -535,6 +544,15 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
values.targets = targets;
|
||||
}
|
||||
|
||||
if (mtaRelay && /^smtps?:/i.test(mtaRelay)) {
|
||||
mtaRelay = {
|
||||
id: new ObjectId(),
|
||||
type: 'relay',
|
||||
value: mtaRelay // current mtaRelay string value
|
||||
};
|
||||
values.mtaRelay = mtaRelay;
|
||||
}
|
||||
|
||||
if ('pubKey' in req.params && !values.pubKey) {
|
||||
values.pubKey = '';
|
||||
}
|
||||
|
@ -796,6 +814,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
.required()
|
||||
.description('Custom internal metadata object set for this user. Not available for user-role tokens'),
|
||||
targets: Joi.array().items(Joi.string()).required().description('List of forwarding targets'),
|
||||
mtaRelay: Joi.string().required().description('MTA Relay url'),
|
||||
spamLevel: Joi.number()
|
||||
.required()
|
||||
.description('Relative scale for detecting spam. 0 means that everything is spam, 100 means that nothing is spam'),
|
||||
|
@ -1073,6 +1092,8 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
.map(target => target.value)
|
||||
.filter(target => target),
|
||||
|
||||
mtaRelay: userData.mtaRelay?.value || false,
|
||||
|
||||
limits: {
|
||||
quota: {
|
||||
allowed: Number(userData.quota) || settings['const:max:storage'],
|
||||
|
@ -1194,6 +1215,14 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
'An array of forwarding targets. The value could either be an email address or a relay url to next MX server ("smtp://mx2.zone.eu:25") or an URL where mail contents are POSTed to'
|
||||
),
|
||||
|
||||
mtaRelay: Joi.string()
|
||||
.uri({
|
||||
scheme: [/smtps?/],
|
||||
allowRelative: false,
|
||||
relativeOnly: false
|
||||
})
|
||||
.description('An address of an SMTP MTA relay. The value should be a relay url. If specified uses the this relay as the outbound MTA.'),
|
||||
|
||||
spamLevel: Joi.number()
|
||||
.min(0)
|
||||
.max(100)
|
||||
|
@ -1326,6 +1355,7 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
|
||||
let targets = values.targets;
|
||||
let existingTargets;
|
||||
let mtaRelay = values.mtaRelay;
|
||||
|
||||
if (targets) {
|
||||
for (let i = 0, len = targets.length; i < len; i++) {
|
||||
|
@ -1382,6 +1412,15 @@ module.exports = (db, server, userHandler, settingsHandler) => {
|
|||
}
|
||||
}
|
||||
|
||||
if (mtaRelay && /^smtps?:/i.test(mtaRelay)) {
|
||||
mtaRelay = {
|
||||
id: new ObjectId(),
|
||||
type: 'relay',
|
||||
value: mtaRelay // current mtaRelay string value
|
||||
};
|
||||
values.mtaRelay = mtaRelay;
|
||||
}
|
||||
|
||||
if (!values.name && 'name' in req.params) {
|
||||
values.name = '';
|
||||
}
|
||||
|
|
|
@ -101,7 +101,8 @@ async function autoreply(options, autoreplyData) {
|
|||
reason: 'autoreply',
|
||||
from: '',
|
||||
to: options.sender,
|
||||
interface: 'autoreplies'
|
||||
interface: 'autoreplies',
|
||||
mtaRelay: options.userData?.mtaRelay || false
|
||||
},
|
||||
(err, ...args) => {
|
||||
if (err || !args[0]) {
|
||||
|
|
|
@ -74,7 +74,8 @@ class FilterHandler {
|
|||
encryptForwarded: true,
|
||||
pubKey: true,
|
||||
spamLevel: true,
|
||||
tagsview: true
|
||||
tagsview: true,
|
||||
mtaRelay: true
|
||||
};
|
||||
|
||||
if (collection === 'users') {
|
||||
|
|
|
@ -13,7 +13,9 @@ module.exports = (options, callback) => {
|
|||
|
||||
targets: options.targets,
|
||||
|
||||
interface: 'forwarder'
|
||||
interface: 'forwarder',
|
||||
|
||||
mtaRelay: options.userData?.mtaRelay || false
|
||||
};
|
||||
|
||||
let message = options.maildrop.push(mail, (err, ...args) => {
|
||||
|
|
|
@ -144,16 +144,42 @@ class Maildropper {
|
|||
|
||||
let deliveries = [];
|
||||
|
||||
let mxData = false;
|
||||
|
||||
if (options.mtaRelay) {
|
||||
// user has MTA Relay set, use it to send outbound email
|
||||
let relayData = options.mtaRelay.value;
|
||||
if (typeof relayData === 'string') {
|
||||
relayData = tools.getRelayData(relayData);
|
||||
}
|
||||
|
||||
mxData = {
|
||||
mx: relayData.mx,
|
||||
mxPort: relayData.mxPort,
|
||||
mxAuth: relayData.mxAuth,
|
||||
mxSecure: relayData.mxSecure,
|
||||
skipSRS: true,
|
||||
skipSTS: true
|
||||
};
|
||||
}
|
||||
|
||||
if (options.targets) {
|
||||
options.targets.forEach(target => {
|
||||
switch (target.type) {
|
||||
case 'mail':
|
||||
deliveries.push({
|
||||
to: target.value,
|
||||
forwardedFor: target.recipient
|
||||
});
|
||||
break;
|
||||
{
|
||||
let delivery = {
|
||||
to: target.value,
|
||||
forwardedFor: target.recipient
|
||||
};
|
||||
|
||||
if (mxData) {
|
||||
delivery = { ...delivery, ...mxData };
|
||||
}
|
||||
|
||||
deliveries.push(delivery);
|
||||
}
|
||||
break;
|
||||
case 'relay':
|
||||
{
|
||||
let recipients = new Set([].concat(options.to || []).concat(target.recipient || []));
|
||||
|
@ -196,9 +222,15 @@ class Maildropper {
|
|||
}
|
||||
|
||||
if (!deliveries.length) {
|
||||
deliveries = envelope.to.map(to => ({
|
||||
to
|
||||
}));
|
||||
deliveries = envelope.to.map(to => {
|
||||
let delivery = { to };
|
||||
|
||||
if (mxData) {
|
||||
delivery = { ...delivery, ...mxData };
|
||||
}
|
||||
|
||||
return delivery;
|
||||
});
|
||||
}
|
||||
|
||||
if (!deliveries.length) {
|
||||
|
|
|
@ -61,7 +61,7 @@ secret=\"$ZONEMTA_SECRET\"
|
|||
algo=\"md5\"" > /etc/zone-mta/plugins/loop-breaker.toml
|
||||
|
||||
echo "[wildduck]
|
||||
enabled=[\"receiver\", \"sender\"]
|
||||
enabled=[\"receiver\", \"sender\", \"main\"]
|
||||
|
||||
# which interfaces this plugin applies to
|
||||
interfaces=[\"feeder\"]
|
||||
|
|
Loading…
Add table
Reference in a new issue