**Domain alias rejected with 550 Relay not allowed on cold cache (LDAP directory backend), still reproducible on v0.16.23**

Issue Description

Mail addressed to a domain alias is rejected with 550 5.1.2 Relay not allowed whenever the domain name is not yet in the local cache (e.g. right after a service restart). Once the primary domain has been resolved by any earlier lookup (cache warm), mail to the alias domain is accepted and routed correctly.

This looks like the same class of issue as the earlier forum topic about domain aliases not working for mailing lists (marked fixed in v0.16.18, commit deb034b), but it is still reproducible on v0.16.23 in our setup. The original report used the internal directory; we use an LDAP (Active Directory) directory backend, so the fix apparently does not cover this code path.

Expected Behavior

RCPT TO for any address at an aliased domain is always accepted (given the address exists), regardless of cache state.

Actual Behavior

After every Stalwart restart (cold cache), RCPT TO to the alias domain fails with 550 5.1.2 Relay not allowed. After a single RCPT TO to the primary domain (which succeeds), the alias domain starts working.

In production this means: every service restart breaks inbound mail to aliased domains until some message to the primary domain happens to arrive. This is non-deterministic from the administrator’s point of view.

Reproduction Steps

  1. Two-node Stalwart cluster, v0.16.23 on both nodes. Directory backend: LDAP (Active Directory). The same LDAP directory is the authentication directory.
  2. Create domain example-primary.test with domain alias example-alias.test. (Alias verified present via JMAP x:Domain/get: "aliases": {"example-alias.test": true}.)
  3. Have an AD account whose proxyAddresses contain both smtp:[email protected] and smtp:[email protected].
  4. Restart the stalwart service.
  5. Plain SMTP session on the port 25 listener:
MAIL FROM:<[email protected]>
RCPT TO:<[email protected]>     -> 550 5.1.2 Relay not allowed.
RCPT TO:<[email protected]>   -> 250 2.1.5 OK
RCPT TO:<[email protected]>     -> 250 2.1.5 OK   (now works!)```

### Relevant Log Output
```# 1st attempt, alias domain, cold cache -> rejected WITHOUT any store/LDAP lookup:
DEBUG Cache miss (store.cache-miss) key = "example-alias.test", collection = "domainName"
INFO  Relay not allowed (smtp.relay-not-allowed) ... to = "[email protected]"

# primary domain -> cache miss on domainId, LDAP query runs, accepted:
DEBUG Cache miss (store.cache-miss) key = 5, collection = "domainId"
TRACE LDAP query executed (store.ldap-query) details = "(|(&(objectCategory=person)(objectClass=user)(|([email protected])([email protected])(proxyAddresses=smtp:[email protected])))...", result = [[... AD user, proxyAddresses include both addresses ...]]
INFO  SMTP RCPT TO command (smtp.rcpt-to) ... to = "[email protected]"

# 2nd attempt, alias domain -> now a cache HIT, LDAP query runs, accepted:
DEBUG Cache hit (store.cache-hit) key = "example-alias.test", collection = "domainName"
TRACE LDAP query executed (store.ldap-query) details = "(|(&(objectCategory=person)(objectClass=user)(|([email protected])([email protected])(proxyAddresses=smtp:[email protected])))...", result = [[... same AD user ...]]
INFO  SMTP RCPT TO command (smtp.rcpt-to) ... to = "[email protected]"```

### Stalwart Version
v0.16.x

### Installation Method
Binary (Linux)

### Database Backend
PostgreSQL

### Blob Storage
S3-compatible

### Search Engine
PostgreSQL

### Directory Backend
LDAP

### Additional Context
- Cluster: 2 nodes, NATS coordination, shared PostgreSQL. Inbound SMTP relayed via Proxmox Mail Gateway.
- Reproduced identically with a second domain pair — same cache-dependent pattern.
- Behavior flips between `550 Relay not allowed` (domain not recognized) and `550 Mailbox does not exist` (domain recognized via warm cache, address lookup path differs) depending on cache state, which made initial diagnosis confusing.
- Workaround meanwhile: per-address aliases in AD `proxyAddresses` for the alias domains. This only helps once the alias domain is recognized — it does not fix the cold-cache rejection.

### I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on

### I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on

### I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I'd prefer a human-only reply, I'll add the no-ai tag to my topic.
on

Since 0.16.18 (the deb034b fix) aliases have their own index, but nothing builds it for aliases that were saved before the upgrade, and saving the domain again with the same aliases doesn’t write it either. Looking up the primary caches every name it has, aliases included, so the alias works from then on. Was example-alias.test added before you upgraded to 0.16.18?

If it was, remove the alias and save, then add it back and save:

stalwart-cli update domain <id> --field 'aliases/example-alias.test=null'
stalwart-cli update domain <id> --field 'aliases/example-alias.test=true'

Then restart one node and repeat your RCPT test. An alias accepted on a cold cache confirms it, and it means the upgrade should have rebuilt that index.