IMAP COPY shares flags between source and destination: STORE \Deleted on the source marks the copy as deleted, breaking COPY+STORE+EXPUNGE moves (Apple Mail 10.13/10.14)

Issue Description

IMAP COPY does not create an independent message: the copy shares its flags with the source. Apple Mail 11.5 (macOS 10.13) and 12.4 (macOS 10.14) move messages with UID COPY + UID STORE +FLAGS (\Deleted) on the source + a later EXPUNGE (they do not use MOVE). On Stalwart the \Deleted set on the source appears on the copy too, so the moved message is hidden in the destination and reappears in the source until expunged; expunging the source leaves it \Deleted in the destination. Stalwart 0.16.20, single node, RocksDB, Linux binary. The 0.16.21–0.16.23 changelogs have no entry about this. Clients using MOVE (recent Apple Mail, iOS, JMAP webmails) are not affected. Distinct from “Pipelined STORE and EXPUNGE can execute out of order”: the order is fine here, the flag is shared.

Expected Behavior

Per RFC 3501 §6.4.7 / RFC 9051 §6.4.7, COPY creates a new message in the destination whose flags are copied at copy time and are independent afterwards. A subsequent STORE \Deleted on the source must not change the flags of the copy.

Actual Behavior

After “UID COPY 3 INBOX” (source Junk, COPYUID → 8826) and “UID STORE 3 +FLAGS.SILENT (\Deleted)” on the source, a FETCH from a separate session shows:
INBOX UID 8826 FLAGS (\Deleted $NotJunk \Seen)
Junk Mail UID 3 FLAGS (\Deleted $NotJunk \Seen)
The client’s INBOX session receives “* 8662 FETCH (FLAGS (\Deleted $NotJunk \Seen) UID 8826)” right after the STORE on the source. The copy is the same object as the source with a second mailbox (JMAP model: one Email, two mailboxIds, one keyword set).

Reproduction Steps

  1. Session A: LOGIN, SELECT “Junk Mail” (any folder with one message, UID 3 here).
  2. A: UID COPY 3 INBOX → OK [COPYUID 3 ]
  3. A: UID STORE 3 +FLAGS.SILENT (\Deleted)
  4. Session B: LOGIN, SELECT INBOX, UID FETCH (FLAGS) → \Deleted is present on the copy.
    No MOVE, no EXPUNGE involved. Reproducible every time with imaplib or openssl s_client; Apple Mail 10.13/10.14 does exactly this sequence on every drag-and-drop move.

Relevant Log Output

2026-09-21T12:58:10Z imap.raw-input contents = “7.35 UID COPY 3 INBOX”
2026-09-21T12:58:10Z imap.copy source = 12, details = [3], accountId = 12, mailboxId = 0, uid = [8826]
2026-09-21T12:58:10Z imap.raw-output contents = “7.35 OK [COPYUID 3197398093 3 8826] UID COPY completed”
2026-09-21T12:58:10Z imap.raw-input contents = “9.35 UID STORE 3 +FLAGS.SILENT (\Deleted)”
2026-09-21T12:58:11Z imap.store accountId = 12, mailboxId = 2, documentId = [134062], type = “Add”, details = [“Deleted”]
2026-09-21T12:58:11Z imap.raw-output contents = “* 3 FETCH (UID 3 MODSEQ (135790)) 9.35 OK UID STORE completed”
2026-09-21T12:58:11Z imap.raw-output (INBOX session) contents = “* 8662 EXISTS”
2026-09-21T12:58:11Z imap.raw-output (INBOX session) contents = “* 8662 FETCH (FLAGS (\Deleted $NotJunk \Seen) UID 8826)”

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

RocksDB

Blob Storage

Filesystem

Search Engine

Internal

Directory Backend

Internal

Additional Context

Clients: Apple Mail 11.5 (macOS 10.13.6) and 12.4 (macOS 10.14.6), IMAPS 993 with Let’s Encrypt, no proxy in front of Stalwart. Server capabilities after login include MOVE, UIDPLUS, CONDSTORE, QRESYNC. Same behaviour observed on two accounts; ~40 users migrated from CommuniGate Pro on 2026-09-19.

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

This is a “won’t fix”. Stalwart is a JMAP first mail server where messages copied within a same account are referenced rather than copied, following the JMAP model. For this reason individual flags per mailbox for a same message are not supported.