What headers can user-provided sieve scripts access?

Your question

Im trying to create a rule acting on the RCPT TO. The Delivered-To-Header sometimes corresponds to this value and does so in my case. The managesieve frontend I am using supports specifying rules matching custom headers. It does not support matching variabels such as those provided by stalwart.

When I create a rule to match on the Delivered-To header, it does not trigger. To debug this I created a rule matching any (*) value in the Delivered-To header, tagging matchend emails red. This rule triggered on emails from mailing lists that contained multiple Delivered-To headers. The one added by stalwart and ones added by upstream MTAs.

This leads me to the theory that the Delivered-To header added by stalwart as seen in my email client is not available at the time of evaluation - either because it is not yet added or because it is somehow shadowed. I remotely remember a discussion on this on previous platforms (discord/github/matrix) but cannot find it anymore.
My understanding was that user-provided sieve scripts are executed after the DATA stage. Since configuration of the Delivered-To header is performed at the DATA stage, I assumed that the header is added before evaluation.

Therefore my question is, when the Delivered-To header is added and ultimately why user-provided sieve scripts do not appear to match on the Delivered-To header?
The more generic question would be, which headers are available to user-provided sieve scripts (not to be confused with the admin-provided user scripts)?
The documentation only provides information on the variables available in the (un)trusted interpreters.

I have confirmed that addition of the Delivered-To header is enabled an working.

I am running stalwart v0.16.x

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

Your theory is right. The Delivered-To header Stalwart adds is written during final ingest, which happens after the user script has run, so a user Sieve rule can never see it. The ones you did see matching are the headers added by upstream MTAs on mailing list mail, which is exactly what you observed.

It is structural rather than a toggle: that header is per-recipient, while the script runs against the single queued copy of the message shared by every recipient. The headers your script does see are the ones on that queued copy: the original message headers plus what the DATA stage prepended, so Received, Authentication-Results and Received-SPF.

For what you actually want, use the envelope test, which holds the final delivery address and is plain RFC 5228, so a frontend that only offers header rules will usually still offer it:

if envelope :is "to" "[email protected]" { fileinto "Folder"; }

If the recipient was rewritten by an alias, catch-all or sub-address, the pre-rewrite address is in envelope "orcpt", with some caveats currently under discussion at Subaddressing information lost after delivery. The docs do not currently state which headers the untrusted interpreter sees, which they should.