Skip to main content

ImapKit

A scriptable, in-memory IMAP server for testing IMAP clients

npm install --save-dev imapkit
A test drives the ImapKit server, which pushes changes to IMAP clients

Strict by design

Client input that breaks the RFCs gets BAD or NO, so client bugs show up in your tests instead of against a production server.

50+ extensions

IMAP4rev1 and IMAP4rev2 with IDLE, CONDSTORE, QRESYNC, NOTIFY, ACL, METADATA, QUOTA, SORT, THREAD, COMPRESS and many more, turned on per server.

Control API

Add messages, change flags, reset UIDVALIDITY and disconnect sessions with server.control. Connected clients see every change.

Scripted faults

Script rules and quirk presets reproduce what real servers do: late responses, split output, throttling, autologout and dropped connections.

Multiple sessions

Several clients on one mailbox get EXISTS, EXPUNGE and flag updates at the points the RFCs allow, following RFC 2180.

Any language

Run the imapkit command with the REST API and server events, and drive it from Python, Go or any other test suite.

A real IMAP server inside your test

ImapKit runs in the same process as your test suite, starts in milliseconds and keeps nothing on disk. Every test gets a fresh server with exactly the mailboxes, messages, users and extensions it needs.

Your client talks real IMAP over a real socket, while the test changes the server underneath it and checks that the client keeps up.

Writing client tests →
client.test.js
import imapkit from 'imapkit';

const server = imapkit({ plugins: ['IDLE', 'CONDSTORE', 'QRESYNC'] });
const port = await server.start();

// ... connect your IMAP client to 127.0.0.1:port as testuser / testpass

// change the server while the client is connected
server.control.addMessage('INBOX', { raw: 'Subject: hello\r\n\r\nHi!\r\n' });
server.control.resetUidValidity('INBOX', { uids: 'shuffle', seed: 1 });

// and make it misbehave like real servers do
server.script.add({ on: 'command', command: 'SELECT', times: 1, send: '$TAG NO [UNAVAILABLE] Try again\r\n' });

await server.stop();