Pipelined STORE and EXPUNGE can execute out of order

Issue Description

Stalwart runs IMAP STORE in a background task. A following pipelined EXPUNGE can run before the \Deleted flag is committed.

The message is not expunged and later reappears in the client.

Seen with Geary, which pipelines UID STORE followed by UID EXPUNGE when deleting messages.

STORE uses a background task, while EXPUNGE runs inline. The fix awaits STORE inline so later commands see the completed update.

Fix and test:

GH: @prasannavl if you’re open to accepting PRs as I have a few more some of which I’ve already created issues for here. Thanks!

Expected Behavior

Pipelined commands should execute in the order received. EXPUNGE should see the flag change made by STORE.

Actual Behavior

EXPUNGE can finish before STORE. It finds no deleted messages, then STORE applies the \Deleted flag afterward.

Reproduction Steps

  1. Select a mailbox containing one message.
  2. Send STORE and EXPUNGE in one pipelined batch:

A1 STORE 1 +FLAGS.SILENT (\Deleted)
A2 EXPUNGE

  1. Select the mailbox again.
  2. The message may still be present with \Deleted set.

Relevant Log Output

A1 OK STORE completed
A2 OK EXPUNGE completed

No EXPUNGE response is returned for the message.

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

LDAP

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

Fixed in v0.16.14 (not yet released).