Outlook draft autosave still races IMAP SEARCH on v0.16

Issue Description

hi, we’re still hitting the Outlook draft issue from this older discussion, now on Stalwart 0.16.14 with Meilisearch.

Outlook APPENDs an autosaved message to Drafts and gets an APPENDUID. It then immediately runs a UID SEARCH. We’ve seen both HEADER Message-ID and 1:* SINCE.

The new UID is already readable with UID FETCH, but that first SEARCH sometimes returns nothing because the external index hasn’t caught up yet. Outlook doesn’t retry. It shows “Outdated Draft / This draft was deleted from another location”, so composing becomes pretty painful.

We have headers enabled in Search.indexEmailFields, so Message-ID search works once indexing catches up. The part that’s still broken is the read-after-write gap.

Expected Behavior

Once APPEND returns APPENDUID, an immediate SEARCH in the same mailbox should be able to find that message, at least for the metadata searches Outlook uses.

Actual Behavior

APPEND succeeds and UID FETCH can see the new message, but an immediate UID SEARCH can return an empty result until Meilisearch indexes the document. Outlook treats that miss as if the draft was deleted.

Reproduction Steps

  1. Configure Stalwart v0.16.x with Meilisearch. Enable header indexing if testing the Message-ID path.
  2. IMAP APPEND a new RFC message to Drafts with the \Draft flag.
  3. Take the UID from APPENDUID and immediately run either:
    • UID SEARCH HEADER Message-ID "the-message-id"
    • UID SEARCH 1:* SINCE 05-Aug-2026
  4. Run UID FETCH for the APPENDUID.
  5. Repeat with no delay between APPEND and SEARCH.

The failure is: SEARCH does not contain the new UID, while UID FETCH already returns it. Each search mode should use its own APPEND so this stays a real single-shot test.

Relevant Log Output

Shortened, sanitized example from our single-shot probe:

C: A1 APPEND "Drafts" (\Draft) {...}
S: A1 OK [APPENDUID 1234 42] APPEND completed

C: A2 UID SEARCH 1:* SINCE 05-Aug-2026
S: * SEARCH
S: A2 OK UID SEARCH completed

C: A3 UID FETCH 42 (UID FLAGS)
S: * 1 FETCH (UID 42 FLAGS (\Draft))
S: A3 OK UID FETCH completed

Stalwart Version

v0.16.x

Installation Method

Docker

Database Backend

PostgreSQL

Blob Storage

S3-compatible

Search Engine

Meilisearch

Directory Backend

Internal

Additional Context

We made a temporary patched build to confirm the cause. For messages appended to Drafts or carrying \Draft, it waits after ingest until the exact account/document ID is visible in the search store before returning APPENDUID. It polls every 25 ms with a 5 second maximum.

That fixed both our single-shot probe and a real Outlook client. When we accidentally ended up back on the stock image, the Outlook dialog came back straight away.

I’m not saying our patch is the right upstream fix, but it confirms the race. Is there a supported way to make this consistent in Stalwart itself? Happy to share the probe and the small patch.

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 has been fixed on the v1.0.0 branch and can’t be backported to v0.16 without a schema migration, see IMAP SEARCH silently omits recently delivered messages when using an external SearchStore (eventual-consistency race)

Note that the UID SEARCH HEADER Message-ID "the-message-id" query won’t work until the index catches up. If that is an issue for Outlook, I suggest you report the problem to Microsoft as searching by message id for a message the client just created moments ago is both inefficient and error prone. IMAP is designed around UID, the message-id header is client defined and does not guarantee uniqueness.

thanks, that makes sense. we’ll keep our patch on v0.16 for now and test v1 before removing it.

one thing i want to make sure i understand: Outlook is definitely issuing UID SEARCH HEADER Message-ID in our traces, not only SINCE. if that path still depends on the external index in v1, then the same race can still happen for Outlook, right?

i understand that searching by Message-ID isn’t ideal, but unfortunately we can’t change what Outlook does. is there any server-side option planned for making that immediate search consistent, or should we assume our barrier will still be needed on v1 for Outlook compatibility?

Yes, Message-Id is a text field so search is delegated to the index.

Searching by Message-Id in itself is fine, what is bad design is to search by Message-Id a message the client itself created, it should keep track of the UID assigned by the server.

Whether a search is immediate or not depends on the search store’s load. There are three options here:

  1. Stalwart could block the account’s search capabilities until the index is ready, but that is not good user experience.
  2. It could also not show the message in the inbox until indexing is done, but that would make the email delivery feel slow to the user.
  3. Or, it can show the message immediately and index the message in the background, since searching for a message that was just received is rare.

We decided to go with option (3) as we think it offers the best trade off.