Using a spamtrap

Your question

I’m trying to use the spam trap feature by following Spamtrap | Stalwart

However, it is really unclear what is required to not get 550 5.1.2 Relay not allowed. error. Do we need to create a real mailbox with a domain? From the documentation it feels that by simply adding it to the spam traps list is enough. It explicitly states that setting SPAM_TRAP SpamTag object to Discard prevents it from reaching a real inbox.

Regardless, it feels kinda “wasteful” to make a real inbox (and hence potentially a domain) for a spam trap.

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

Yes — adding an address to the spam-trap list alone does not make the SMTP server accept mail for it. The spam-trap tagging only happens during the DATA-stage spam filter analysis, which runs after the recipient has already been accepted at RCPT TO. Recipient acceptance is governed entirely by normal mailbox/domain resolution logic: Stalwart checks whether the address belongs to a known account, a catch-all address, or a domain with relaying enabled — if none of those match, it returns 550 5.1.2 Relay not allowed, regardless of whether the address happens to be in your spam-trap list.

So to use a spamtrap address without the “Relay not allowed” error, the address needs to resolve successfully at RCPT TO time via one of these mechanisms:

  • A real mailbox for that address, or
  • A catch-all address configured on the domain (so any local-part at that domain resolves), or
  • The domain flagged to allow relaying for that address.

Once the recipient is accepted, the message proceeds to spam filtering, where a match against the spam-trap list applies the SPAM_TRAP tag (score 15.0 by default). If you then set that SpamTag’s action to Discard (via the SpamTag object under Spam Filter → Settings → Scores), the message is silently dropped instead of reaching an inbox — but the recipient still has to be a resolvable address for the SMTP transaction to get that far. There’s no way to accept RCPT TO purely because an address is listed as a spam trap; a catch-all domain address is the lightest-weight way to satisfy that requirement without provisioning full mailboxes.

Reference: Spamtrap | Stalwart

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

Reminder/bug, make sure to invalidate caches when adding a domain + catch all address! Else you would still get relay not allowed.

Your workaround is actually the right setup, and the docs page should have said so. The trap is matched inside the spam filter, which runs at DATA, whereas recipient validation happens back at RCPT TO. So an address that isn’t a deliverable local recipient gets its 550 long before anything looks at the trap list. Domain plus a catch-all is exactly the intended shape.

That also answers the Discard question: the tag action controls what happens after the message has been accepted, so it can’t suppress a relay rejection. And there’s a catch with Discard I’d flag, since the page suggests it: a tag mapped to Discard short-circuits scoring before the auto-learn step, so the trap stops feeding the classifier entirely. If training is the point of the trap, leave it at the default score of 15 and the mail files itself to Junk, which is harmless on a parked domain nobody reads. Training also needs the Bayes classifier enabled, and samples only take effect on the next training cycle rather than immediately.

On the cache point from your second post, which version are you on, and did you add the domain and catch-all through the web UI or the CLI? I want to know whether that was a normal cache TTL or a missing invalidation on create.

Awesome as always, clear!

On caching, i am quite sure all was via CLI (JMAP) and I was running .17 (I think this one) or 0.16. That said I was doing many things in parallel so don’t spent too much time hunting this one.

Actually, considering I have global spam reject set at 20, there is a high chance the mail is rejected and the spam trap does not really behave as a spam trap right?

To be honest, there are many edges cases for spam traps. From an operator point of view it feels a spam trap should not behave like a normal mailbox as there are many edge cases. Moreover, it is “harder” to debug. I think it makes sense to have a dedicated spam trap thing that takes care of all this without needing all of the extra (non-obvious) pipe work.

However, this is quickly becoming a future request…