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,idleandIdleall 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=SEARCHandCONTEXT=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,
pluginsaccepts 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.
| Plugin | Also loads |
|---|---|
IMAP4rev2 | ENABLE, 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 |
QRESYNC | ENABLE, CONDSTORE |
UIDONLY, UTF8=ACCEPT, METADATA, METADATA-SERVER | ENABLE |
SEARCHRES, PARTIAL, MULTISEARCH, CONTEXT=SEARCH | ESEARCH |
ESORT | SORT, ESEARCH |
CONTEXT=SORT | ESORT, SORT, ESEARCH, CONTEXT=SEARCH |
SORT=DISPLAY | SORT |
LIST-STATUS | LIST-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:
| Combination | Error | Reason |
|---|---|---|
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 SAVELIMIT | SAVELIMIT can not be enabled together with MESSAGELIMIT | RFC 9738 section 3: a server advertises one of the two |
IMAP4rev2 and the no-move or no-uidplus quirk | IMAP4rev2 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
| Plugin | Capability | RFC | Summary | Page |
|---|---|---|---|---|
ACL | ACL, RIGHTS=texk, LIST-MYRIGHTS | 4314, 8440 | Access control lists, enforced for users other than the owner | Access control |
APPENDLIMIT | APPENDLIMIT, APPENDLIMIT=<n> | 7889 | Largest message APPEND accepts, per server or per mailbox | Messages |
AUTH-PLAIN | AUTH=PLAIN | 4616 | AUTHENTICATE PLAIN | Authentication and transport |
BINARY | BINARY | 3516 | Decoded body parts in FETCH, literal8 messages in APPEND | Messages |
CATENATE | CATENATE, URL-PARTIAL | 4469, 5550 | APPEND builds a message from literals and IMAP URLs | Messages |
COMPRESS | COMPRESS=DEFLATE | 4978 | DEFLATE compression of the connection | Authentication and transport |
CONDSTORE | CONDSTORE | 7162 | Mod-sequences, CHANGEDSINCE, UNCHANGEDSINCE | Synchronization |
CONTEXT-SEARCH | CONTEXT=SEARCH | 5267 | Updating search results, CANCELUPDATE | Search and sort |
CONTEXT-SORT | CONTEXT=SORT | 5267 | Updating sort results | Search and sort |
CREATE-SPECIAL-USE | CREATE-SPECIAL-USE | 6154 | CREATE name (USE (...)) | Mailboxes |
ENABLE | ENABLE | 5161 | The ENABLE command | Synchronization |
ESEARCH | ESEARCH | 4731 | SEARCH RETURN (MIN MAX ALL COUNT) | Search and sort |
ESORT | ESORT | 5267 | SORT RETURN (...) | Search and sort |
ID | ID | 2971 | The ID command | Authentication and transport |
IDLE | IDLE | 2177 | Push notifications while idling | Synchronization |
IMAP4rev2 | IMAP4rev2 | 9051 | IMAP4rev2 for sessions that ENABLE it | IMAP4rev2 |
LIST-EXTENDED | LIST-EXTENDED | 5258 | LIST selection and return options | Mailboxes |
LIST-STATUS | LIST-STATUS | 5819 | LIST ... RETURN (STATUS (...)) | Mailboxes |
LITERALMINUS | LITERAL- | 7888 | Non-synchronizing literals up to 4096 octets | Messages |
LITERALPLUS | LITERAL+ | 7888 | Non-synchronizing literals of any size | Messages |
LOGINDISABLED | LOGINDISABLED | 3501 | LOGIN refused without TLS | Authentication and transport |
MESSAGELIMIT | MESSAGELIMIT=<n> | 9738 | Commands work on at most n messages | Messages |
METADATA | METADATA | 5464 | Server and mailbox annotations | Metadata and quota |
METADATA-SERVER | METADATA-SERVER | 5464 | Server annotations only | Metadata and quota |
MOVE | MOVE | 6851 | MOVE and UID MOVE | Messages |
MULTIAPPEND | MULTIAPPEND | 3502 | Several messages in one APPEND | Messages |
MULTISEARCH | MULTISEARCH | 7377 | The ESEARCH command over several mailboxes | Search and sort |
NAMESPACE | NAMESPACE | 2342 | The NAMESPACE command | Mailboxes |
NOTIFY | NOTIFY | 5465 | Events for the selected and other mailboxes | Synchronization |
OAUTHBEARER | AUTH=OAUTHBEARER | 7628 | OAuth 2.0 bearer token login | Authentication and transport |
OBJECTID | OBJECTID | 8474 | MAILBOXID, EMAILID, THREADID | Synchronization |
PARTIAL | PARTIAL | 9394 | Paged SEARCH results and FETCH | Search and sort |
PREVIEW | PREVIEW | 8970 | The PREVIEW FETCH item | Messages |
QRESYNC | QRESYNC | 7162 | Quick resynchronization, VANISHED | Synchronization |
QUOTA | QUOTA, QUOTA=RES-STORAGE, QUOTA=RES-MESSAGE, QUOTA=RES-MAILBOX, QUOTASET | 9208 | Quota roots, limits and OVERQUOTA | Metadata and quota |
REPLACE | REPLACE | 8508 | REPLACE and UID REPLACE | Messages |
SASL-IR | SASL-IR | 4959 | Initial response in AUTHENTICATE | Authentication and transport |
SAVEDATE | SAVEDATE | 8514 | The save date of a message | Messages |
SAVELIMIT | SAVELIMIT=<n> | 9738 | COPY and APPEND of at most n messages | Messages |
SEARCHRES | SEARCHRES | 5182 | SEARCH RETURN (SAVE) and $ | Search and sort |
SORT | SORT | 5256 | SORT and UID SORT | Search and sort |
SORT-DISPLAY | SORT=DISPLAY | 5957 | DISPLAYFROM and DISPLAYTO sort keys | Search and sort |
SPECIAL-USE | SPECIAL-USE | 6154 | Special-use mailbox attributes | Mailboxes |
STARTTLS | STARTTLS | 3501 | The STARTTLS command | Authentication and transport |
STATUS-SIZE | STATUS=SIZE | 8438 | The SIZE STATUS item | Mailboxes |
THREAD-ORDEREDSUBJECT | THREAD=ORDEREDSUBJECT | 5256 | THREAD with the ORDEREDSUBJECT algorithm | Search and sort |
THREAD-REFERENCES | THREAD=REFERENCES | 5256 | THREAD with the REFERENCES algorithm | Search and sort |
UIDONLY | UIDONLY | 9586 | No message sequence numbers after ENABLE | Synchronization |
UIDPLUS | UIDPLUS | 4315 | APPENDUID, COPYUID, UID EXPUNGE | Messages |
UNAUTHENTICATE | UNAUTHENTICATE | 8437 | Back to the Not Authenticated state | Authentication and transport |
UNSELECT | UNSELECT | 3691 | Close a mailbox without expunging | Mailboxes |
UTF8-ACCEPT | UTF8=ACCEPT | 9755 | UTF-8 mailbox names and strings after ENABLE | Messages |
X-GM-EXT-1 | X-GM-EXT-1 | Gmail | Gmail message ids, thread ids, labels and X-GM-RAW | Gmail |
XOAUTH2 | AUTH=XOAUTH2 | Gmail style OAuth 2.0 login | Authentication 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/balso createsaas a normal mailbox if it does not exist (RFC 3501 section 6.3.3). An existing\Noselectlevel stays\Noselect. - DELETE of a mailbox with children leaves a
\Noselectlevel 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": falseSTORE accepts exactly the flags PERMANENTFLAGS lists (permanentFlagsand 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-ASCIIandUTF-8charsets. Any other charset getsNO [BADCHARSET (US-ASCII UTF-8)].
The Mailboxes page shows these in transcripts, and Strict by design lists what the core refuses.