IMAP protocol support

maild serves IMAP over implicit TLS. Sessions start in IMAP4rev1 compatibility mode; ENABLE IMAP4rev2 switches to rev2 responses and UTF-8 mailbox names. ENABLE UTF8=ACCEPT enables UTF-8 while retaining rev1 SEARCH responses. Rev1 mailbox names use modified UTF-7, including &- for a literal ampersand. Non-canonical shifts, including shifted printable ASCII, fail with BAD. CREATE, RENAME and subscriptions share Net-Unicode character validation, including C1 control rejection. Explicit CHARSET US-ASCII and CHARSET UTF-8 work in every SEARCH mode.

Commands and extensions

SurfaceBehaviourWire coverage in services/maild/tests/imap_rev2.rs
MIME FETCHStored encoded content, nested part paths, MIME and forwarded-message selectors, PEEK and octet partials; numbering follows BODYSTRUCTUREthunderbird_mime_parts_on_demand_and_structure_agree
FETCH structuresBODY omits extension fields; FAST, ALL and FULL expand to their standard data itemsfetch_macros_and_non_extensible_body
BINARYTransfer decoding, decoded SIZE and partials; literal8 for NUL; UNKNOWN-CTE on decoding failuresbinary_decodes_sizes_partials_literal8_and_seen, binary_unknown_and_malformed_transfer_encoding_fail
ENABLEIMAP4rev2 and UTF8=ACCEPT; unknown capabilities ignoredenable_rev2_esearch_save_and_dollar_survive_expunge, utf8_mailbox_names_and_rev1_modified_utf7_roundtrip
ESEARCH / SEARCHRESMIN, MAX, ALL, COUNT, SAVE and $; saved identities remain UIDs across expungesenable_rev2_esearch_save_and_dollar_survive_expunge, legacy_search_and_save_min_max_with_uid_copy_and_store
STATUSSIZE, DELETED and configured APPENDLIMIT, alongside existing counters and rev1 RECENTstatus_aggregates_and_appendlimit_match_config
LISTSUBSCRIBED, REMOTE, RECURSIVEMATCH, CHILDREN, SPECIAL-USE, multiple patterns and LIST-STATUS; LIST and LSUB reference nameslist_extended_references_patterns_status_and_special_use
CREATE-SPECIAL-USECREATE USE assigns one supported role to the leaf, with atomic uniqueness enforcementExisting imap_phase2 CREATE USE tests
LiteralsBounded segmented framing for command arguments, literal8 and MULTIAPPEND; pre-auth resource limits remain strictergeneral_literals_login_names_flags_search_and_multiappend, utf8_append_wrapper_and_literal_kind_are_checked
Atomic APPENDAll message rows, projections, memberships and UID allocations commit togethermultiappend_failure_leaves_no_partial_messages, multiappend_storage_failure_rolls_back_all_rows_and_uids
RENAME INBOXMove current messages to a new mailbox; keep INBOX identity, UIDNEXT and childrenrename_inbox_preserves_identity_children_and_moves_messages
UIDPLUS / COPY / MOVEAPPENDUID and COPYUID; atomic COPY; MOVE reports COPYUID before EXPUNGEcopy_failure_rolls_back_earlier_destinations_and_uidnext, existing imap_phase4_copy_move_expunge tests
Read-only and CLOSEEXAMINE never sets Seen; CLOSE quietly expunges only a writable mailbox; UNSELECT retains deleted messagesexamine_fetch_and_close_unselect_have_distinct_effects
NotificationsPreserve client MSNs until expunges can be reported; announce observed additions; IDLE reports flags with UIDspending_expunge_preserves_msns_until_a_permitted_command, existing imap_phase5_idle tests
SubscriptionsNames survive RENAME and DELETE; LIST SUBSCRIBED identifies absent mailboxessubscriptions_survive_rename_and_delete_and_absent_names_can_be_removed
ShutdownFinish the current response, send BYE, flush and release connection slotsshutdown_sends_bye_during_idle_and_releases_account_slot
Selected read costCheap native mailbox change tokens avoid unchanged snapshots; FETCH resolves only requested UIDs through the membership indexten_thousand_messages_use_indexed_fetch_and_single_idle_membership_reads
RENAME notificationsEmit exact mailbox identities and descendants with OLDNAME; wildcard characters in names remain literalrev2_rename_reports_exact_ids_and_old_names_including_descendants

The selected-read cost test uses 10,000 messages and 1,000 single-message FETCHes, counting native store calls. It also checks 100 IDLE flag events without relisting the mailbox and one catch-up diff for an unknown UID. Ordinary notifications use the mailbox's native change counter, including flag changes and removals.

Contiguous requested UID runs use one membership-index range scan each. Full-folder FETCH uses one scan even when expunges left UID holes. A transient IDLE snapshot failure produces UNAVAILABLE and preserves the session and its view for retry on the next event. The wire regression also counts full-folder and sparse FETCH scans and injects a failed IDLE catch-up before retrying it.

selected_imap_view_observes_cross_session_jmap_smtp_and_sieve_changes selects a mailbox, performs unchanged FETCHes, then checks NOOP notifications after other IMAP sessions append and expunge, JMAP Email/set changes memberships, SMTP delivers mail, and Sieve files SMTP mail into the selected mailbox. Account deletion is also tested through the application and property-store SQLite connections: both enable foreign keys and cascade Sieve scripts, versions and vacation stamps.

SAVE failures clear $, including grammar errors. Successful DELETE of the selected mailbox returns to authenticated state, with CLOSED in rev2. Missing subscription rows carry both NonExistent and Noselect; subscription-only children use CHILDINFO without changing a live mailbox's HasChildren attribute. The empty LIST pattern remains a delimiter probe when RETURN options are present, and LIST-STATUS APPENDLIMIT uses the session configuration.

SEARCH scans decoded MIME content without making whole-message lowercased copies. Its substring matcher uses linear work and memory proportional to the needle. Content-dependent searches refuse messages above the 64 MiB work limit with NO [LIMIT]; they do not return incomplete matches. A query-weighted 256 MiB scan budget also bounds repeated predicates against one message (repeated_content_searches_share_a_per_message_work_budget). Metadata-only searches can still match these messages. Unreadable content produces NO [UNAVAILABLE].

Binary APPEND preserves decoded body octets while storing NUL-bearing leaf parts with base64 transfer encoding. This keeps ordinary BODY responses valid IMAP strings; BINARY returns the original decoded octets. Unsupported binary encodings or NUL in message headers fail with UNKNOWN-CTE. UTF8=ACCEPT also supports the UTF8 (~{N}...) APPEND form. Embedded-message reparsing shares a 64-level budget across binary APPEND normalisation (binary_append_bounds_reparsed_message_nesting). BINARY accepts both padded and unpadded MIME base64. RFC822 and RFC822.TEXT set Seen; RFC822.HEADER and read-only FETCHes do not. RENAME INBOX retains each membership's flags and user keywords.

Capabilities come from an implementation allowlist. Operator overrides can select a subset but cannot add unimplemented extensions. APPENDLIMIT always comes from imap_max_literal_bytes. LITERAL+ permits non-synchronising literals up to the configured cap; a LITERAL- override limits non-synchronising literals to 4096 octets while permitting larger synchronising literals. Command-wide allocation and literal-count limits apply as well. Input that cannot be safely drained closes the connection instead of being interpreted as new commands. The two protocol capabilities remain present even with an operator override.

Original refusal inventory

These are the refusal sites found before implementation. Comments and tests containing the same wording are included so an obsolete phase note cannot be mistaken for a remaining protocol limit.

Original site under services/maild/src/imap/Resolution
capabilities.rs: unimplemented overrides accepted; LITERAL- filtered; stale IDLE examplesImplementation allowlist, dynamic APPENDLIMIT and literal sizing policy
codec.rs: unstripped literal refusal; mid-command literal refusal; SEARCH-only multi-literal documentationGeneral segmented session framing, retaining bounded refusal and FramingLost paths
op/fetch.rs: part-addressing deferrals, BODY refusal and macro refusalsMIME traversal, non-extensible BODY and macro expansion
op/search.rs: SEARCH RETURN refusalESEARCH and session SEARCHRES state
op/status.rs: SIZE/DELETED deferrals and unsupported-item rejectionMembership aggregates and APPENDLIMIT; unknown items still fail
op/list.rs: non-empty reference and extension-option refusalsExtended parser, reference resolution and LIST-STATUS
op/lsub.rs: non-empty reference refusalSame reference resolution as LIST
op/rename.rs: INBOX deferralAtomic storage operation retaining the INBOX container
op/store.rs: user keywords described as deferredDocumentation corrected; per-membership keywords remain supported
op/create.rs: transactional parent-walk deferralParent creation remains incremental; message operations use atomic transactions. A failed leaf creation may leave newly created parents, which a retry reuses
op/select.rs: CONDSTORE/QRESYNC parameter refusal; op/fetch.rs: MODSEQ refusal; op/store.rs: UNCHANGEDSINCE deferralIntentional dependency on the complete imap-ext implementation; not advertised or enabled here
sasl.rs: unsupported proxy authzidDeliberate: empty authzid and authzid equal to authcid work; cross-account proxy authentication is not offered
op/authenticate.rs: unsupported SASL mechanismDeliberate rejection of mechanisms outside AUTH=PLAIN and AUTH=LOGIN
op/check.rs: “deferred mailbox state”; session.rs: matching CHECK commentDescriptive only: CHECK has no pending storage work to flush
session.rs: unknown UID inner command and generic phase refusalInvalid commands remain BAD; all standard UID subcommands are dispatched
session.rs: STARTTLS refusalExplicit implicit-TLS-only policy; no cleartext IMAP listener is offered

Additional RFC 9051 audit findings

The audit also checked server requirements beyond the refusal strings:

Requirement groupFinding and resolution
Sections 4, 5.1 and Appendix A: strings and namesAdded UTF-8 negotiation, modified UTF-7 compatibility, NFC validation and literal-kind tracking
Sections 2.3.1.1 and 6.3.4: recreated mailbox identityPersistent UIDVALIDITY high-water mark for new mailboxes, seeded from current wire identities and time. Legacy millisecond values convert to their existing seconds value, preserving client caches. RENAME allocates a fresh value only for a renamed mailbox whose identity collides with another live mailbox or a recorded retired value. DELETE and collision repair retain old values, protecting earlier cached names after rename-away/delete sequences. legacy_identities_migrate_before_login_and_cannot_collide_after_rename and rename_repairs_only_colliding_live_or_deleted_name_identities cover both paths
Sections 5.2 and 7.5.1: mailbox updates and MSN stabilityAdded command-time refresh and preserved views while expunge notifications are prohibited
Sections 6.3.2–6.3.3: selection data and read-only flagsAccurate LIST attributes and OLDNAME in rev2; CLOSED boundaries on reselection, including failed SELECT; RECENT/UNSEEN in rev1; empty PERMANENTFLAGS for EXAMINE. Covered by rev2_reselection_marks_the_closed_boundary_including_failure and examine_fetch_and_close_unselect_have_distinct_effects
Section 6.3.4: existing mailbox creationCorrected old idempotent CREATE INBOX and CREATE existing/ behaviour to NO
Sections 6.3.5–6.3.8: mailbox lifecycleDELETE removes memberships atomically, protects children and INBOX; subscription names persist
Sections 6.3.12 and 6.4.7: mutation failureAdded atomic MULTIAPPEND and COPY, including UID allocation rollback
Sections 6.4.1–6.4.2: CLOSE and UNSELECTCorrected CLOSE’s missing expunge; UNSELECT remains non-expunging
Sections 6.4.4–6.4.5 and 7.5.2: search and body dataAdded ESEARCH, SAVE lifetime, charset handling, body forms, encoded sections and decoded binary sizes
Sections 6.1.3, 7.1 and 7.2: responsesFinal capability list after authentication; operational UNAVAILABLE errors; shutdown BYE
Sections 6.4.8–6.4.9: MOVE and UIDPLUSRetained COPYUID-before-EXPUNGE ordering, UID EXPUNGE filtering and implicit UID FETCH items

UID ordering, immutable message identities, authentication, NAMESPACE, UNSELECT, literal abuse caps and the existing MOVE/UIDPLUS behaviours retain their original regression suites. The release tests are necessary evidence; this document does not claim certification by every mail client.

CONDSTORE, QRESYNC, MODSEQ, UNCHANGEDSINCE and STATUS HIGHESTMODSEQ are integration hooks for work/maild-imap-ext. ENABLE ignores those names and omits an empty ENABLED response until that complete implementation lands. STARTTLS remains refused under the implicit TLS policy.

Protocol references: RFC 9051, BINARY, ENABLE, SEARCHRES, LIST-EXTENDED, UTF8=ACCEPT, APPENDLIMIT.

This page as Markdown · This page describes the current main branch of MixOS.