Repository navigation
fix: protocol bugs found in the documentation review - #95
Merged
Merged
Conversation
In a mailbox with allowPermanentFlags false, SELECT listed the flags its messages have or had in PERMANENTFLAGS, but STORE and the control API checked only the permanentFlags of the mailbox and dropped the others. Both now use server.isPermanentFlag(), the same list SELECT sends, and APPEND and COPY leave out flags the mailbox can not store instead of turning them into new keywords (RFC 3501 section 7.1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An empty LIST reference means the mailbox name is interpreted as by SELECT (RFC 3501 section 6.3.8, RFC 9051 section 6.3.9), so LIST "" "INBOX.%" lists the children of INBOX in a Cyrus style "INBOX." namespace and LIST "" "%" lists INBOX. Namespaces other than the personal one are still hidden from wildcards unless the pattern names their prefix. LIST with an empty mailbox name returns the delimiter and root of the reference namespace. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RFC 3516 and RFC 9051 section 6.4.5 define no error for a part number that does not exist, and RFC 3516 section 4.2 gives BINARY the semantics of BODY, so the empty string ImapKit (and Dovecot) send stays. The code comments no longer claim that RFC 3501 section 6.4.5 requires it, and the BINARY docs describe the behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…RCH responses RFC 3501 section 7.4.1 forbids only EXPUNGE during FETCH, STORE and SEARCH, and section 5.2 requires mailbox size updates during a command. Commands that refer to messages now first send the EXISTS and flag updates of other sessions that were queued before any pending EXPUNGE, so a session never gets a FETCH response for a message it was not told about. What was queued after a pending EXPUNGE still waits for it, as do the sequence number forms of COPY and MOVE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…UNGE UID SEARCH with message numbers in the criteria keeps the EXPUNGE responses of other sessions back like SEARCH does, but ended with a plain OK. It now carries EXPUNGEISSUED too (RFC 5530 section 3, RFC 9051 section 7.1), as do UID SORT and UID THREAD with message numbers in the criteria. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…attr CREATE W (USE (NIL)) crashed with NO [SERVERBUG]. RFC 6154 section 6 defines use-attr-ext = "\" atom, so NIL, quoted strings, literals, numbers and atoms without a backslash are BAD, and unsupported attributes keep getting NO [USEATTR] (section 3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
For <@route.example:a@b.c> the route leaked into the mailbox name of the ENVELOPE address. RFC 9051 section 7.5.2 makes the second field the at-domain-list (the obs-route of RFC 5322 section 4.4) and the third the local-part, so the route now goes to addr-adl as "@route.example", the way Dovecot sends it (golden form in test/fixtures/mime/source-route.eml). SORT FROM/TO/CC use the local part too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sessionTimeout came from hoodiecrow and was stored and defaulted to an hour but never used, access tokens do not expire. Enforcing it would make the default token of a long running server stop working after an hour, so it stays accepted and is marked deprecated in the types and docs, which now show how to test an expired token with control.updateUser(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After login, AUTHENTICATE with an unknown mechanism got NO while a known one got BAD. AUTHENTICATE is only valid in the not authenticated state (RFC 3501 section 6.2), so both are now BAD with the same text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RFC 5464 section 4.1: a server that sends unsolicited METADATA responses MUST support the ENABLE command, and sends them only after ENABLE METADATA (or METADATA-SERVER). Without the ENABLE plugin a client could not turn them on, so both plugins now list ENABLE in plugin.requires, like UTF8=ACCEPT and UIDONLY. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lues A storage message with an internaldate like "Thu, 1 Jan 2026 10:00:00 +0000" was accepted, FETCH then sent an invalid INTERNALDATE and SORT ARRIVAL fell back. validateStorage now requires a date-time string of a real date and time (RFC 3501 section 9) or a valid Date for internaldate and SAVEDATE (RFC 8514 section 4.2), so the server fails when it is built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RFC 3501 section 7.3.2: the RECENT response occurs "if the size of the mailbox changes (e.g., new messages)" and the client MUST record it. A run of EXISTS responses that announces new messages (from another session, the session's own APPEND, COPY or MOVE, SMTP or the control API) is now followed by one RECENT response with the number of \Recent messages the session knows. With NOTIFY it follows the FETCH of the new message (RFC 5465 section 5.2). Sessions that enabled IMAP4rev2 do not get it (RFC 9051 Appendix E). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
no-move and no-uidplus removed MOVE and UIDPLUS even when IMAP4rev2 was loaded, which advertised IMAP4rev2 without the MOVE command, UID EXPUNGE, APPENDUID and COPYUID that RFC 9051 folds into the base protocol (Appendix E). The server constructor now throws "IMAP4rev2 requires MOVE, which the "no-move" quirk removes" when a loaded plugin requires a plugin a quirk removes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…essions Real transcripts for new messages reported before FETCH responses, a new message that waits for a pending EXPUNGE, UID SEARCH with OK [EXPUNGEISSUED] and the RECENT response after EXISTS. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RFC 3501 section 6.3.8 and RFC 9051 section 6.3.9: with the namespace convention "#" is a break out character "and must be treated as such", so LIST "Work/" "#news.*" lists the #news. namespace instead of looking for "Work/#news.*". CLAUDE.md describes the new notification timing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Unknown AUTHENTICATE mechanisms run through the command queue with a fallback handler, so the central checks (state, script rules, commandChecks) apply as for every command - Reuse isAtom for EXISTS, EXPUNGE and CREATE-SPECIAL-USE checks, the ATOM-CHAR grammar of imap-handler for use-attr, and getNamespace for LIST with an empty mailbox name - One RECENT helper that counts the session's \Recent set, one snapshot lookup per flush, the sequence number check cached per command, one pattern per namespace in matchFolders - One permanent flag list for PERMANENTFLAGS and STORE, one storage date check, one user credentials type, the quirk requires check inside the plugin loader Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the server bugs found while writing and verifying the imapkit.com docs. Each fix was checked against the RFC text and has tests.
OK [EXPUNGEISSUED]like SEARCH, and IMAP4rev1 sessions get RECENT after new messages (RFC 3501 7.3.2).INBOX.(RFC 3501 6.3.8), and#is a break-out character that overrides the reference.CREATE ... (USE (NIL))is BAD instead of a SERVERBUG crash (RFC 6154), and AUTHENTICATE after login is BAD whatever the mechanism. Storage internal dates must be RFC 3501 date-time values.xoauth2.sessionTimeoutis deprecated because it was never enforced.The docs and README are updated to match.
/simplifyand/security-reviewran over the branch; the security review found nothing.🤖 Generated with Claude Code