Skip to main content

Extensions overview

ImapKit implements IMAP4rev1 (RFC 3501) in its core. Every IMAP extension, including IMAP4rev2 itself, is a plugin that you turn on per server instance. A server without plugins is a plain IMAP4rev1 server, so you can test how your client behaves against a minimal server and against a server with every extension, using the same storage.

Enabling plugins​

Pass the plugin names in the plugins option:

import imapkit from 'imapkit';

const server = imapkit({
plugins: ['IDLE', 'MOVE', 'UIDPLUS', 'CONDSTORE', 'ENABLE']
});
await server.start(1143);

From the command line, use --plugin (repeated or comma separated) or the IMAPKIT_PLUGINS environment variable. A config file given with --config can list them in its plugins array too. See Command line.

imapkit -p 1143 --plugin=IDLE,MOVE --plugin=CONDSTORE
IMAPKIT_PLUGINS=IDLE,MOVE imapkit -p 1143

Plugins are loaded when the server is created. They can not be loaded or unloaded while it runs.

Plugin names​

  • Names are case-insensitive: IDLE, idle and Idle all load the same plugin.
  • The name is the plugin's file name (status-size, x-gm-ext-1, literalplus), and the capability spelling works too where it differs: LITERAL+, LITERAL-, AUTH=PLAIN, AUTH=XOAUTH2, AUTH=OAUTHBEARER, COMPRESS=DEFLATE, STATUS=SIZE, SORT=DISPLAY, THREAD=ORDEREDSUBJECT, THREAD=REFERENCES, UTF8=ACCEPT, CONTEXT=SEARCH and CONTEXT=SORT.
  • A plugin listed more than once is loaded once.
  • An unknown name throws an error that lists the available plugins:
Unknown plugin "FOO". Available plugins: acl, appendlimit, auth-plain, binary, ...
  • Besides names, plugins accepts functions, which is how custom plugins are loaded.

Plugins that load other plugins​

Some extensions are defined on top of others, so their plugins load what they need. The load order does not matter.

PluginAlso loads
IMAP4rev2ENABLE, NAMESPACE, UNSELECT, UIDPLUS, ESEARCH, SEARCHRES, IDLE, SASL-IR, LIST-EXTENDED, LIST-STATUS, MOVE, BINARY, SPECIAL-USE, STATUS=SIZE, AUTH=PLAIN, and LITERAL- unless LITERAL+ is loaded
QRESYNCENABLE, CONDSTORE
UIDONLY, UTF8=ACCEPT, METADATA, METADATA-SERVERENABLE
SEARCHRES, PARTIAL, MULTISEARCH, CONTEXT=SEARCHESEARCH
ESORTSORT, ESEARCH
CONTEXT=SORTESORT, SORT, ESEARCH, CONTEXT=SEARCH
SORT=DISPLAYSORT
LIST-STATUSLIST-EXTENDED

Plugins that can be turned on with ENABLE (CONDSTORE, QRESYNC, UIDONLY, UTF8=ACCEPT, IMAP4rev2, METADATA, METADATA-SERVER) work in any order with the ENABLE plugin. CONDSTORE also works without ENABLE, through SELECT ... (CONDSTORE) and the other commands that turn it on.

Some plugins only add to others when both are loaded: LIST-MYRIGHTS comes with ACL plus LIST-EXTENDED, the SPECIAL-USE LIST options combine with LIST-EXTENDED, /private/specialuse comes with METADATA plus SPECIAL-USE, and so on. Each page below lists these combinations.

Combinations that throw​

A few extensions exclude each other, and loading both throws an error when the server is created:

CombinationErrorReason
LITERAL+ and LITERAL-LITERAL- can not be enabled together with LITERAL+ (or the other way round)RFC 7888 section 5: a server must not advertise both
MESSAGELIMIT and SAVELIMITSAVELIMIT can not be enabled together with MESSAGELIMITRFC 9738 section 3: a server advertises one of the two
IMAP4rev2 and the no-move or no-uidplus quirkIMAP4rev2 requires MOVE, which the "no-move" quirk removes (or UIDPLUS)RFC 9051 Appendix E: IMAP4rev2 folds in MOVE and UIDPLUS

IMAP4rev2 loads LITERAL- only when LITERAL+ is not loaded, and a LITERAL+ loaded after it replaces that implied LITERAL-, so ['IMAP4rev2', 'LITERAL+'] works.

Self-contained plugins​

A plugin that is not loaded leaves no trace. Without CONDSTORE, messages have no MODSEQ value and SELECT INBOX (CONDSTORE) is answered with BAD. Without MOVE, MOVE is an unknown command. This lets you check that your client only uses what the server advertises.

The no-uidplus and no-move quirk presets remove UIDPLUS and MOVE even when the plugin list names them. With IMAP4rev2, which requires both (RFC 9051 Appendix E), they throw IMAP4rev2 requires MOVE, which the "no-move" quirk removes (or the same for UIDPLUS) when the server is created.

Capabilities​

Every loaded plugin adds its capability to the CAPABILITY response, after IMAP4rev1. Some capabilities depend on the session state. For example AUTH=PLAIN, SASL-IR and LOGINDISABLED are only listed before login, STARTTLS only on a connection without TLS:

C: A1 CAPABILITY
S: * CAPABILITY IMAP4rev1 AUTH=PLAIN SASL-IR
S: A1 OK Completed
C: A2 AUTHENTICATE PLAIN AHRlc3R1c2VyAHRlc3RwYXNz
S: A2 OK User logged in
C: A3 CAPABILITY
S: * CAPABILITY IMAP4rev1
S: A3 OK Completed

Built-in plugins​

PluginCapabilityRFCSummaryPage
ACLACL, RIGHTS=texk, LIST-MYRIGHTS4314, 8440Access control lists, enforced for users other than the ownerAccess control
APPENDLIMITAPPENDLIMIT, APPENDLIMIT=<n>7889Largest message APPEND accepts, per server or per mailboxMessages
AUTH-PLAINAUTH=PLAIN4616AUTHENTICATE PLAINAuthentication and transport
BINARYBINARY3516Decoded body parts in FETCH, literal8 messages in APPENDMessages
CATENATECATENATE, URL-PARTIAL4469, 5550APPEND builds a message from literals and IMAP URLsMessages
COMPRESSCOMPRESS=DEFLATE4978DEFLATE compression of the connectionAuthentication and transport
CONDSTORECONDSTORE7162Mod-sequences, CHANGEDSINCE, UNCHANGEDSINCESynchronization
CONTEXT-SEARCHCONTEXT=SEARCH5267Updating search results, CANCELUPDATESearch and sort
CONTEXT-SORTCONTEXT=SORT5267Updating sort resultsSearch and sort
CREATE-SPECIAL-USECREATE-SPECIAL-USE6154CREATE name (USE (...))Mailboxes
ENABLEENABLE5161The ENABLE commandSynchronization
ESEARCHESEARCH4731SEARCH RETURN (MIN MAX ALL COUNT)Search and sort
ESORTESORT5267SORT RETURN (...)Search and sort
IDID2971The ID commandAuthentication and transport
IDLEIDLE2177Push notifications while idlingSynchronization
IMAP4rev2IMAP4rev29051IMAP4rev2 for sessions that ENABLE itIMAP4rev2
LIST-EXTENDEDLIST-EXTENDED5258LIST selection and return optionsMailboxes
LIST-STATUSLIST-STATUS5819LIST ... RETURN (STATUS (...))Mailboxes
LITERALMINUSLITERAL-7888Non-synchronizing literals up to 4096 octetsMessages
LITERALPLUSLITERAL+7888Non-synchronizing literals of any sizeMessages
LOGINDISABLEDLOGINDISABLED3501LOGIN refused without TLSAuthentication and transport
MESSAGELIMITMESSAGELIMIT=<n>9738Commands work on at most n messagesMessages
METADATAMETADATA5464Server and mailbox annotationsMetadata and quota
METADATA-SERVERMETADATA-SERVER5464Server annotations onlyMetadata and quota
MOVEMOVE6851MOVE and UID MOVEMessages
MULTIAPPENDMULTIAPPEND3502Several messages in one APPENDMessages
MULTISEARCHMULTISEARCH7377The ESEARCH command over several mailboxesSearch and sort
NAMESPACENAMESPACE2342The NAMESPACE commandMailboxes
NOTIFYNOTIFY5465Events for the selected and other mailboxesSynchronization
OAUTHBEARERAUTH=OAUTHBEARER7628OAuth 2.0 bearer token loginAuthentication and transport
OBJECTIDOBJECTID8474MAILBOXID, EMAILID, THREADIDSynchronization
PARTIALPARTIAL9394Paged SEARCH results and FETCHSearch and sort
PREVIEWPREVIEW8970The PREVIEW FETCH itemMessages
QRESYNCQRESYNC7162Quick resynchronization, VANISHEDSynchronization
QUOTAQUOTA, QUOTA=RES-STORAGE, QUOTA=RES-MESSAGE, QUOTA=RES-MAILBOX, QUOTASET9208Quota roots, limits and OVERQUOTAMetadata and quota
REPLACEREPLACE8508REPLACE and UID REPLACEMessages
SASL-IRSASL-IR4959Initial response in AUTHENTICATEAuthentication and transport
SAVEDATESAVEDATE8514The save date of a messageMessages
SAVELIMITSAVELIMIT=<n>9738COPY and APPEND of at most n messagesMessages
SEARCHRESSEARCHRES5182SEARCH RETURN (SAVE) and $Search and sort
SORTSORT5256SORT and UID SORTSearch and sort
SORT-DISPLAYSORT=DISPLAY5957DISPLAYFROM and DISPLAYTO sort keysSearch and sort
SPECIAL-USESPECIAL-USE6154Special-use mailbox attributesMailboxes
STARTTLSSTARTTLS3501The STARTTLS commandAuthentication and transport
STATUS-SIZESTATUS=SIZE8438The SIZE STATUS itemMailboxes
THREAD-ORDEREDSUBJECTTHREAD=ORDEREDSUBJECT5256THREAD with the ORDEREDSUBJECT algorithmSearch and sort
THREAD-REFERENCESTHREAD=REFERENCES5256THREAD with the REFERENCES algorithmSearch and sort
UIDONLYUIDONLY9586No message sequence numbers after ENABLESynchronization
UIDPLUSUIDPLUS4315APPENDUID, COPYUID, UID EXPUNGEMessages
UNAUTHENTICATEUNAUTHENTICATE8437Back to the Not Authenticated stateAuthentication and transport
UNSELECTUNSELECT3691Close a mailbox without expungingMailboxes
UTF8-ACCEPTUTF8=ACCEPT9755UTF-8 mailbox names and strings after ENABLEMessages
X-GM-EXT-1X-GM-EXT-1GmailGmail message ids, thread ids, labels and X-GM-RAWGmail
XOAUTH2AUTH=XOAUTH2GoogleGmail style OAuth 2.0 loginAuthentication and transport

The Plugin column shows the file name spelling. The capability spellings listed under Plugin names work as well, and so do the spellings with = for the names that have it (CONTEXT=SEARCH, SORT=DISPLAY, STATUS=SIZE, UTF8=ACCEPT ...). imapkit --help prints the same list with a short description of every plugin.

What core IMAP4rev1 supports​

Without any plugin, ImapKit supports every RFC 3501 command: CAPABILITY, NOOP, LOGOUT, LOGIN, AUTHENTICATE (no mechanism is built in, so it answers NO Unsupported authentication mechanism until an AUTH plugin is loaded, and BAD after login), SELECT, EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB, STATUS, APPEND, CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY and the UID variants of COPY, FETCH, STORE and SEARCH. STARTTLS is a plugin.

Some choices that the RFCs leave to the server:

  • The subscription list holds names, not mailboxes (RFC 3501 section 6.3.6). DELETE does not unsubscribe, so LSUB and LIST (SUBSCRIBED) keep listing the name until UNSUBSCRIBE, and a mailbox created again under that name is subscribed. RENAME leaves the subscription with the old name. A mailbox from the storage object is subscribed unless it has "subscribed": false, a new mailbox is not. SUBSCRIBE refuses names that are not mailboxes, UNSUBSCRIBE accepts any name.
  • CREATE a/b also creates a as a normal mailbox if it does not exist (RFC 3501 section 6.3.3). An existing \Noselect level stays \Noselect.
  • DELETE of a mailbox with children leaves a \Noselect level that keeps nothing but the children. CREATE of that name makes a new mailbox with a new UIDVALIDITY.
  • A keyword stays in the FLAGS and PERMANENTFLAGS of a mailbox once a message in it had the keyword, also after that message is expunged (RFC 3501 section 7.2.6). In a mailbox with "allowPermanentFlags": false STORE accepts exactly the flags PERMANENTFLAGS lists (permanentFlags and the flags its messages have or had) and ignores the others, APPEND and COPY leave them out (RFC 3501 section 7.1).
  • An obsolete source route in an address (<@route.example:a@b.c>, RFC 5322 section 4.4) goes to the at-domain-list field of the ENVELOPE address ((NIL "@route.example" "a" "b.c")), the mailbox name is the local part only (RFC 9051 section 7.5.2), like Dovecot sends it.
  • SEARCH, SORT and THREAD support the US-ASCII and UTF-8 charsets. Any other charset gets NO [BADCHARSET (US-ASCII UTF-8)].

The Mailboxes page shows these in transcripts, and Strict by design lists what the core refuses.