From 19a942f67c078bf30581ad02a7fbc4da51299b5a Mon Sep 17 00:00:00 2001 From: Maurus Decimus <11444311+mdecimus@users.noreply.github.com> Date: Sat, 6 Jun 2026 09:36:35 +0200 Subject: [PATCH] Fix MTA: Sub-addressing with external directories returns `550 Mailbox not found` --- CHANGELOG.md | 1 + crates/common/src/network/mta.rs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2155872d..79887e67 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ If you are upgrading from v0.16.x, replace the binary (or run `docker pull`). If - OAuth: Rework access tokens to an `AES-256-GCM-SIV` AEAD format that carries the account name for proxy routing and revokes tokens on credential change. ## Fixed +- MTA: Sub-addressing with external directories returns `550 Mailbox not found`. ## [0.16.7] - 2026-05-28 diff --git a/crates/common/src/network/mta.rs b/crates/common/src/network/mta.rs index 681ec0aa..413337eb 100644 --- a/crates/common/src/network/mta.rs +++ b/crates/common/src/network/mta.rs @@ -108,19 +108,28 @@ impl Server { .get_directory_for_cached_domain(&domain) .filter(|directory| directory.can_lookup_recipients()); if let Some(directory) = directory { - let address = if local_part.as_ref() == local_part_orig { - Cow::Borrowed(rcpt) - } else { + let is_subaddressed = local_part.as_ref() != local_part_orig; + let address = if is_subaddressed { Cow::Owned(format!("{local_part}@{domain_part}")) + } else { + Cow::Borrowed(rcpt) }; match directory.recipient(address.as_ref()).await? { Recipient::Account(account) => { Box::pin(self.synchronize_account(account)).await?; - return Ok(RcptResolution::Accept); + return Ok(if is_subaddressed { + RcptResolution::Rewrite(address.into_owned()) + } else { + RcptResolution::Accept + }); } Recipient::Group(group) => { Box::pin(self.synchronize_group(group)).await?; - return Ok(RcptResolution::Accept); + return Ok(if is_subaddressed { + RcptResolution::Rewrite(address.into_owned()) + } else { + RcptResolution::Accept + }); } Recipient::Invalid => {} }