Redirect without keep in user Sieve script creates implicit local copy (RFC 5228 violation)

Issue Description

A user Sieve script using redirect without keep (as per RFC 5228) still delivers a local copy to the Inbox. According to the RFC, redirect alone should suppress the implicit keep, meaning no local copy should be stored.

redirect "[email protected]";

Expected Behavior

Mail is forwarded externally, no local copy in Inbox.

RFC 5228, Section 4.1:

If the redirect action is used and no keep or fileinto actions are used,
the message is not implicitly kept.

Actual Behavior

Mail is forwarded successfully AND a copy appears in the local Inbox.

Reproduction Steps

  1. Create user account on Stalwart
  2. Upload Sieve script via ManageSieve or Admin-UI containing only redirect “[email protected]”;
  3. Send a mail to that account
  4. Mail arrives at external address AND in local Inbox

Tested with both immediate delivery and after queue retry — both result in a local copy being kept.

Relevant Log Output

delivery.delivered: to="[email protected]", code=250, details="Ok: 34009 bytes queued"
delivery.completed: elapsed=1000ms

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

PostgreSQL

Blob Storage

PostgreSQL

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 redirect and implicit keep behavior.

The key finding is at lines 489-491:

// Fail-safe, no discard and no keep seen, assume that something went wrong and file anyway.
if !do_deliver && !do_discard {
    messages[0].file_into.push(INBOX_ID);
}

Now let me check how do_deliver is set to understand whether redirect sets it:

Fixed. The fix will be included in v0.16.9.