Fix MTA: Disabled aliases continue receiving messages

This commit is contained in:
Maurus Decimus
2026-06-06 10:48:48 +02:00
parent 19a942f67c
commit d26e9b3d4e
4 changed files with 92 additions and 21 deletions

View File

@@ -52,6 +52,8 @@ pub struct EmailAddressRef<'x> {
pub enum EmailCache {
Account(u32),
MailingList(u32),
DisabledAccountAddress(u32),
DisabledListAddress(u32),
}
#[derive(Debug, Clone)]
@@ -101,6 +103,7 @@ pub struct RoleCache {
#[derive(Debug, Clone)]
pub struct MailingListCache {
pub addresses: Box<[EmailAddress]>,
pub recipients: Arc<[Box<str>]>,
}
@@ -245,7 +248,11 @@ impl CacheItemWeight for RoleCache {
impl CacheItemWeight for MailingListCache {
fn weight(&self) -> u64 {
std::mem::size_of::<MailingListCache>() as u64
//+ self.addresses.iter().map(|s| s.len() as u64).sum::<u64>()
+ self
.addresses
.iter()
.map(|s| s.local_part.len() as u64 + std::mem::size_of::<EmailAddress>() as u64)
.sum::<u64>()
+ self.recipients.iter().map(|s| s.len() as u64).sum::<u64>()
}
}

View File

@@ -327,9 +327,14 @@ impl Server {
}
CacheInvalidation::Account(id) => {
cache.accounts.remove(id);
cache.emails.inner().retain(
|_, v| !matches!(v, EmailCache::Account(account_id) if account_id == id),
);
cache.emails.inner().retain(|_, v| {
!matches!(
v,
EmailCache::Account(account_id)
| EmailCache::DisabledAccountAddress(account_id)
if account_id == id
)
});
}
CacheInvalidation::DkimSignature(id) => {
cache.dkim_signers.remove(id);
@@ -342,9 +347,14 @@ impl Server {
}
CacheInvalidation::List(id) => {
cache.lists.remove(id);
cache.emails.inner().retain(
|_, v| !matches!(v, EmailCache::MailingList(list_id) if list_id == id),
);
cache.emails.inner().retain(|_, v| {
!matches!(
v,
EmailCache::MailingList(list_id)
| EmailCache::DisabledListAddress(list_id)
if list_id == id
)
});
}
CacheInvalidation::DomainLogo(id) => {
self.inner

View File

@@ -230,8 +230,35 @@ impl Server {
{
let item_id = object.id().document_id();
let result = match object.object() {
ObjectType::Account => EmailCache::Account(item_id),
ObjectType::MailingList => EmailCache::MailingList(item_id),
ObjectType::Account => {
if self
.account(item_id)
.await
.caused_by(trc::location!())?
.addresses
.iter()
.any(|address| {
address.local_part.as_ref() == local_part
&& address.domain_id == domain_id
})
{
EmailCache::Account(item_id)
} else {
EmailCache::DisabledAccountAddress(item_id)
}
}
ObjectType::MailingList => {
if let Some(list) = self.try_list(item_id).await?
&& !list.addresses.iter().any(|address| {
address.local_part.as_ref() == local_part
&& address.domain_id == domain_id
})
{
EmailCache::DisabledListAddress(item_id)
} else {
EmailCache::MailingList(item_id)
}
}
_ => {
return Err(trc::AuthEvent::Error
.into_err()
@@ -422,10 +449,16 @@ impl Server {
domain_id: account.domain_id.document_id(),
}]
.into_iter()
.chain(account.aliases.into_iter().map(|alias| EmailAddress {
local_part: alias.name.into(),
domain_id: alias.domain_id.document_id(),
}))
.chain(
account
.aliases
.into_iter()
.filter(|alias| alias.enabled)
.map(|alias| EmailAddress {
local_part: alias.name.into(),
domain_id: alias.domain_id.document_id(),
}),
)
.collect(),
id_tenant: account.member_tenant_id.map(|id| id.document_id()),
id_member_of: account
@@ -479,10 +512,16 @@ impl Server {
domain_id: account.domain_id.document_id(),
}]
.into_iter()
.chain(account.aliases.into_iter().map(|alias| EmailAddress {
local_part: alias.name.into(),
domain_id: alias.domain_id.document_id(),
}))
.chain(
account
.aliases
.into_iter()
.filter(|alias| alias.enabled)
.map(|alias| EmailAddress {
local_part: alias.name.into(),
domain_id: alias.domain_id.document_id(),
}),
)
.collect(),
id_tenant: account.member_tenant_id.map(|id| id.document_id()),
id_member_of: Default::default(),
@@ -764,9 +803,22 @@ impl Server {
let Some(list) = self.registry().object::<MailingList>(id.into()).await? else {
return Ok(None);
};
let cache = Arc::new(MailingListCache {
recipients: list.recipients.into_iter().map(Into::into).collect(),
});
let cache =
Arc::new(MailingListCache {
addresses: [EmailAddress {
local_part: list.name.into(),
domain_id: list.domain_id.document_id(),
}]
.into_iter()
.chain(list.aliases.into_iter().filter(|alias| alias.enabled).map(
|alias| EmailAddress {
local_part: alias.name.into(),
domain_id: alias.domain_id.document_id(),
},
))
.collect(),
recipients: list.recipients.into_iter().map(Into::into).collect(),
});
let _ = guard.insert(cache.clone());
Ok(Some(cache))
}