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
- Two-node Stalwart cluster, v0.16.23 on both nodes. Directory backend: LDAP (Active Directory). The same LDAP directory is the authentication directory.
- Create domain
example-primary.testwith domain aliasexample-alias.test. (Alias verified present via JMAPx:Domain/get:"aliases": {"example-alias.test": true}.) - Have an AD account whose
proxyAddressescontain bothsmtp:[email protected]andsmtp:[email protected]. - Restart the
stalwartservice. - 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