From 19a7dc3092ec02e106c332c6866b9edcd9ff6626 Mon Sep 17 00:00:00 2001 From: John Coffey Date: Fri, 30 Oct 2026 14:51:27 -0700 Subject: [PATCH] Relays: each relay's MX preference A relay's settings get its MX preference, beside its public name: where this server publishes a domain's DNS, the relays are its MX set (relay spec, RL-25). A server from before that sends none, and the field reads 10, the server's default. The help for Linked said turning a relay off closes its port 25. It doesn't: the relay keeps its mail and goes on taking mail in, held, and the help now says so. The public name's help says it goes in the MX and SPF records. --- src/features/relays/RelaysPage.tsx | 26 +++++++++++++++++++++++--- src/features/relays/model.test.ts | 1 + src/features/relays/model.ts | 2 ++ src/help/texts.ts | 6 ++++-- src/i18n/en.json | 3 ++- 5 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/features/relays/RelaysPage.tsx b/src/features/relays/RelaysPage.tsx index b044772..7aaec7d 100644 --- a/src/features/relays/RelaysPage.tsx +++ b/src/features/relays/RelaysPage.tsx @@ -288,6 +288,7 @@ interface General { description: string; address: string; linkPort: string; + mxPreference: string; enabled: boolean; sendThrough: boolean; inboundOnly: boolean; @@ -299,6 +300,7 @@ function general(relay: Relay): General { description: relay.description, address: relay.address, linkPort: String(relay.linkPort), + mxPreference: String(relay.mxPreference ?? 10), enabled: relay.enabled, sendThrough: relay.sendThrough, inboundOnly: relay.inboundOnly, @@ -354,6 +356,13 @@ function SettingsDialog({ } patch.linkPort = Number(g.linkPort); } + if (g.mxPreference !== startGeneral.mxPreference) { + if (!/^\d+$/.test(g.mxPreference) || Number(g.mxPreference) > 65535) { + setInvalid('mxPreference'); + return; + } + patch.mxPreference = Number(g.mxPreference); + } for (const flag of ['enabled', 'sendThrough', 'inboundOnly'] as const) { if (g[flag] !== startGeneral[flag]) patch[flag] = g[flag]; } @@ -443,9 +452,20 @@ function SettingsDialog({

{t('relays.s.receiving', 'Taking mail in')}

- - {input('hostname', { placeholder: 'mx1.example.com' })} - +
+ + {input('hostname', { placeholder: 'mx1.example.com' })} + + + setG({ ...g, mxPreference: e.target.value })} + /> + +
{input('smtpListen', { placeholder: '[::]:25' })} diff --git a/src/features/relays/model.test.ts b/src/features/relays/model.test.ts index 9f2ff20..909f028 100644 --- a/src/features/relays/model.test.ts +++ b/src/features/relays/model.test.ts @@ -69,6 +69,7 @@ function relay(extra: Partial = {}): Relay { enabled: true, sendThrough: false, inboundOnly: false, + mxPreference: 10, settings: SETTINGS, joinState: 'joined', links: [link('1')], diff --git a/src/features/relays/model.ts b/src/features/relays/model.ts index 85f4987..2782a2b 100644 --- a/src/features/relays/model.ts +++ b/src/features/relays/model.ts @@ -63,6 +63,8 @@ export interface Relay { enabled: boolean; sendThrough: boolean; inboundOnly: boolean; + /** Absent from servers before RL-25. */ + mxPreference?: number; settings: RelaySettings; joinState: 'waiting' | 'expired' | 'joined'; joinExpiresAt?: string | null; diff --git a/src/help/texts.ts b/src/help/texts.ts index d02f190..336d255 100644 --- a/src/help/texts.ts +++ b/src/help/texts.ts @@ -25,13 +25,15 @@ export const FIELD_HELP: Record = { 'The relay’s host name or IP address, as this server dials it for the link. A WireGuard address keeps the link off the internet.', 'inbuxa:Relay.linkPort': 'The port the relay listens on for this server’s link. 443 unless you chose another.', 'inbuxa:Relay.enabled': - 'Turn off to drop the link: the relay closes port 25 and keeps what it holds until it’s turned back on.', + 'Turn off to stop this server linking to it. The relay keeps the mail it holds and goes on taking mail in, held until it’s turned back on.', 'inbuxa:Relay.sendThrough': 'Send all outgoing mail through relays instead of straight from this server. Mail waits here while no relay is linked.', 'inbuxa:Relay.inboundOnly': 'The relay takes mail in but sends none, for instance while its address is new to other providers or not in your SPF record yet.', 'inbuxa:Relay.hostname': - 'The relay’s public name: what it says when other servers connect, and the name on its certificate. Needs an A record and matching reverse DNS.', + 'The relay’s public name: what it says when other servers connect, and the name on its certificate. Needs an A record and matching reverse DNS. Where this server publishes a domain’s DNS, it’s in the MX and SPF records.', + 'inbuxa:Relay.mxPreference': + 'Where this server publishes a domain’s DNS, the relay’s MX preference: senders try the lowest first. Give relays the same number to share the mail.', 'inbuxa:Relay.smtpListen': 'The addresses the relay takes mail on, usually [::]:25 for every address on port 25.', 'inbuxa:Relay.maxMessageSize': 'The largest message the relay accepts, in either direction.', 'inbuxa:Relay.maxRecipients': 'How many recipients one message may have at the relay.', diff --git a/src/i18n/en.json b/src/i18n/en.json index c22b59a..bbdbfb8 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -2388,7 +2388,8 @@ "spoolMaxBytes": "Spool size (GB)", "outboundRetry": "Waits between attempts", "outboundExpiry": "Give up after", - "outboundTls": "Encryption" + "outboundTls": "Encryption", + "mxPreference": "MX preference" }, "cancel": "Cancel", "addGo": "Add", -- 2.54.0