mail: check for outbound ipv6 connectivity

This commit is contained in:
Girish Ramakrishnan
2025-11-19 16:29:53 +01:00
parent b53da61e7c
commit 141bdb1307

View File

@@ -212,22 +212,25 @@ async function listDomains() {
return results;
}
async function checkOutboundPort25() {
return await new Promise((resolve) => {
async function checkOutboundPort25(family) {
const ip = family === 4 ? await network.getIPv4() : await network.getIPv6();
if (ip === null) return; // ipv4/ipv6 is disabled
return await new Promise((resolve, reject) => {
const client = new net.Socket();
client.setTimeout(5000);
client.connect({ port: 25, host: constants.PORT25_CHECK_SERVER, family: 4 }); // family is 4 to keep it predictable
client.connect({ port: 25, host: constants.PORT25_CHECK_SERVER, family }); // family is 4 to keep it predictable
client.on('connect', function () {
client.destroy(); // do not use end() because it still triggers timeout
resolve({ status: 'passed', message: 'Port 25 (outbound) is unblocked' });
resolve();
});
client.on('timeout', function () {
client.destroy();
resolve({ status: 'failed', message: `Connect to ${constants.PORT25_CHECK_SERVER} timed out. Check if port 25 (outbound) is blocked` });
reject(new Error(`IPv${family} connect to ${constants.PORT25_CHECK_SERVER} timed out`));
});
client.on('error', function (error) {
client.destroy();
resolve({ status: 'failed', message: `Connect to ${constants.PORT25_CHECK_SERVER} failed: ${error.message}. Check if port 25 (outbound) is blocked` });
reject(new Error(`IPv${family} connect to ${constants.PORT25_CHECK_SERVER} failed: ${error.message}`));
});
});
}
@@ -236,7 +239,15 @@ async function checkSmtpRelay(relay) {
assert.strictEqual(typeof relay, 'object');
if (relay.provider === 'noop') return { status: 'skipped', message: 'Outbound disabled' };
if (relay.provider === 'cloudron-smtp') return await checkOutboundPort25();
if (relay.provider === 'cloudron-smtp') {
const results = await Promise.allSettled([ checkOutboundPort25(4), checkOutboundPort25(6) ]);
if (results[0].status === 'fulfilled' && results[1].status === 'fulfilled') return { status: 'passed', message: 'Port 25 (outbound) is unblocked' };
const messages = [];
if (results[0].status === 'rejected') messages.push(results[0].reason.message);
if (results[1].status === 'rejected') messages.push(results[1].reason.message);
messages.push('Check if port 25 (outbound) is blocked.');
return { status: 'failed', message: messages.join('. ') };
}
const options = {
connectionTimeout: 5000,