Sieve scripts are still wonky

Issue Description

Such script used in RCPT_TO stage fails, with “5.1.2 Mailbox does not exist” while everything looks fine in the notified message.

require ["variables", "envelope", "regex", "editheader", "enotify"];


if allof( envelope :localpart :contains "to" ".",
          envelope :regex "to" "fwd\.([^.]+)@(.+)$") 
{
    set "envelope.to" "user+${1}@${2}";
    notify :message "Testing ${envelope.to}/initially ${0}" :from "user@domain" "mailto:[email protected]";
    addheader "X-Alias" "${1}";
    stop;
}

I’m trying address rewriting in Sieve in order to set an custom header storing the initial “to” address since the direct rewriting rule fails in user script (“envelope.to” doesn’t contain the subaddressing part in user script’s sieve).

Yet, the output envelope.to from the sieve script here is correct in the notified message but Stalwart still reject the mail with “Mailbox does not exist” error.

Tried the rewriting without the subaddressing (set "envelope.to" "user@${2}";) and it still is rejected.

Expected Behavior

Stalwart shouldn’t mess with envelope.to subaddressing (the part after the “+” in user+something@domain) when it reaches the user script. Because it doesn’t work, Stalwart should accept address rewriting in a system sieve script and later check the resulting envelope.to address that the script generated, not the initial address.

Actual Behavior

The mail is rejected with 5.1.2 Mailbox does not exist.

Reproduction Steps

Set a system script with the content above (and adapt the domain and user account to your system and the notified email for debugging). Send a mail to fwd.something@yourdomain.
Observe Stalwart rejecting the mail instead of accepting it.

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

PostgreSQL

Blob Storage

Filesystem

Search Engine

Internal

Directory Backend

Internal

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

Let me research how Stalwart handles Sieve envelope rewriting and the RCPT_TO stage.

In the end, I figured out a hacky way. I’m parsing the “To” header in the user script, since this isn’t modified by the system.

None of the sieve features are working. The notify trick is very helpful to figure out what’s going on.

The issue with sieves are:

In system script

  1. In the RCPT_TO stage, setting envelope.to seems to work in the script itself, but Stalwart still use the initial value for validating the account and thus fail with Mailbox doesn’t exist error. This is opposite to the documentation that shows a rewrite example that doesn’t work.
  2. Adding an header in the RCPT_TO stage is completely ignored in the next stages. The header isn’t in the final delivered mail. Maybe it’s expected, but there’s no error whatsoever in the logs. I haven’t tried in the DATA stage, maybe it works here

In user script

  1. The subaddressing doesn’t appear in the envelope.to variable at this stage making filtering and sorting the mail impossible (this used to work in 0.15.x). envelope.to at this step only contains the final delivered email (the same content as in the Delivered-To header)
  2. Nor does if envelope :detail “to” works at this step
  3. Accessing ${2} anywhere in the script doesn’t return an error, but instead give some values L. This is unexpected (I was using the 2nd catch group of a regex that should have been empty, but it contained L instead)
  4. regex matches on a text where it shouldn’t. Sometimes, I have to double escape a special char (like \\. but not \\+) in the script. Try matching [email protected] with just fwd\.bob@domain\.com and it’ll fail. But [email protected] matches fine with fwd\+bob@domain\\.com.

Please check the other topics about using orcpt in v0.16.6.