This is a data-loss bug in the Maildir backend. Since upstream commit
1ca157124 (April 2020, for neomutt issue #2077), a message whose file
disappears between two mailbox checks is kept in the index and marked
deleted+purge. If the file comes back under a new name with the same
canonical filename (which is what every flag change by another
program—offlineimap, mbsync, notmuch, a second NeoMutt—looks like when
it races with the check), the next check matches it and updates the
path and flags but keeps the deleted flag. The next sync ($, changing
folder, quitting) then unlinks the real file.
In my case 22 messages I had only read were unlinked locally and the
IMAP sync deleted them on the server (details in
https://github.com/neomutt/neomutt/issues/4332#issuecomment-6697941615).
They were recoverable only because Gmail keeps deleted mail in Trash.
A reproduction script that needs only one neomutt instance and a
temporary Maildir (no real mail) is attached. With 20250510+dfsg-2 it
prints "files after sync: 2" (one message unlinked); the expected
result is 3. The code is unchanged in 20260616+dfsg-1 and in upstream
main, which also reproduce.
I have sent a fix upstream: https://github.com/neomutt/neomutt/pull/5073
It makes NeoMutt do what OG Mutt does and removes vanished messages
from the index. A new NT_MAILBOX_PRUNE notification removes
quasi_deleted emails and nothing else, so pending user deletes and
other unsynced changes survive the reopen (unlike NT_MAILBOX_UPDATE,
which drops all deleted emails). mh had the same "message has
disappeared" case without any removal and now uses the same path. The
patch is attached and applies to the Debian source with minor offsets.
I tested this pretty thoroughly with a tmux-driven script against a
temp Maildir: a vanished-then-renamed file is no longer unlinked on
sync; d then $ still deletes; a file removed for good disappears from
the index with no dead entry; a message vanishing while open in the
pager doesn't crash; a pending D on another message survives the
reopen and is honored on sync; same vanish/return sequence on an MH
folder.
I think this is my first attempt to contribute to NeoMutt or Mutt, at
least at anything near this complexity, so I'd definitely appreciate
extra eyes on this one. Due to lack of familiarity, and as the commit
message says, the patch was also developed with generative AI (Claude
Fable 5.1), although more in a human-assistance sense.