Installation

Requirements
- Node.js version 20.0 or higher
- npm or yarn package manager
ImapFlow also runs on Bun, Deno, Cloudflare Workers, celld and in browsers, see Other runtimes below.
Install via npm
Install ImapFlow using npm:
npm install imapflow
Install via yarn
Alternatively, you can use yarn:
yarn add imapflow
ES Modules and CommonJS
ImapFlow is published as a dual package with an ES module build and a CommonJS build. Use whichever module system your project uses, the API is the same.
import { ImapFlow } from 'imapflow';
const { ImapFlow } = require('imapflow');
The default export is an object with the ImapFlow and AuthenticationFailure classes, so import imapflow from 'imapflow' followed by new imapflow.ImapFlow() works as well. The examples in this documentation use require(), every one of them works the same way with import.
TypeScript Support
ImapFlow is written in TypeScript and ships its type declarations with the package, one set for each build. No additional @types packages are needed.
import { ImapFlow } from 'imapflow';
const client: ImapFlow = new ImapFlow({
host: 'imap.example.com',
port: 993,
secure: true,
auth: {
user: 'user@example.com',
pass: 'password'
}
});
The option, result and event types are exported from the package root, so a program can name them directly. The AuthenticationFailure error class, the ImapFlowError shape of the errors the client rejects with, and the ImapFlowErrorCode object of known error codes (for checks like err.code === ImapFlowErrorCode.NoConnection) are exported as well.
import type { ImapFlowOptions, FetchMessageObject, MailboxObject, SearchObject, ImapFlowEvents } from 'imapflow';
import { AuthenticationFailure, ImapFlowErrorCode } from 'imapflow';
const options: ImapFlowOptions = {
host: 'imap.example.com',
port: 993,
secure: true,
auth: {
user: 'user@example.com',
pass: 'password'
},
logger: false
};
Events are typed from the event name, so the listener of client.on('exists', ...) receives the ExistsEvent object without an annotation. Every optional property accepts an explicit undefined, so the declarations also work with exactOptionalPropertyTypes enabled.
Other Runtimes
The ES module build runs on Bun, tested against the latest Bun release, on Deno, on Cloudflare Workers with the nodejs_compat compatibility flag, on celld, and in browsers.
compatibility_flags = ["nodejs_compat"]
On Workers, implicit TLS (secure: true, usually port 993) and cleartext work over the default node:net and node:tls. A STARTTLS upgrade over them fails with a TLS error, because the runtime can only upgrade a socket that has no read in flight. Connect through createSocketsTransport() to use STARTTLS on Workers (ImapFlow 2.5.0 or newer):
import { connect } from 'cloudflare:sockets';
import { ImapFlow, createSocketsTransport } from 'imapflow';
const client = new ImapFlow({
host: 'imap.example.com',
port: 143,
doSTARTTLS: true,
auth: { user: 'user@example.com', pass: 'password' },
transport: createSocketsTransport(connect)
});
The runtime does not allow turning certificate validation off, so tls: { rejectUnauthorized: false } is rejected with ERR_OPTION_NOT_IMPLEMENTED (with the transport: UnsupportedTransportOption). COMPRESS=DEFLATE, IDLE and the default Pino logger work as on Node.js.
Deno
ImapFlow runs on Deno 2 through its npm compatibility layer. Import it with an npm: specifier, or add it to the project with deno add npm:imapflow and import it as imapflow. The shipped type declarations are picked up by deno check as well.
import { ImapFlow } from 'npm:imapflow';
const client = new ImapFlow({
host: 'imap.example.com',
port: 993,
secure: true,
auth: {
user: 'user@example.com',
pass: 'password'
},
logger: false
});
await client.connect();
console.log(await client.status('INBOX', { messages: true }));
await client.logout();
The program needs network, environment and hostname access. The environment and hostname permissions are required even with logger: false, because the Pino logger is loaded together with the library and reads both when it loads.
deno run --allow-net=imap.example.com:993 --allow-env --allow-sys=hostname main.js
Implicit TLS, STARTTLS, tls: { rejectUnauthorized: false }, COMPRESS=DEFLATE, IDLE and the default Pino logger work as on Node.js. The differences show up only when the server ends the connection abruptly:
- If the server sends a response and closes the connection immediately after it, Deno reports the close before that response is processed. The connection is still closed and every pending command is rejected, but a final
BYEtext does not make it intoerror.reasonorclient.byeReason, and a server that drops the connection right after accepting STARTTLS produces aClosedAfterConnectTexterror without thetlsFailedflag. - A connection reset after the TLS layer is established is reported as
ClosedAfterConnectTLSinstead ofECONNRESET.
celld
celld is a self-hosted runtime for Cloudflare-style Workers. It has no node:net, node:tls or node:dns, so connect through the transport option with the connect() of cloudflare:sockets (ImapFlow 2.5.0 or newer). Without it, connect() fails with "node:net.connect is not implemented in celld".
import { connect } from 'cloudflare:sockets';
import { ImapFlow, createSocketsTransport } from 'imapflow';
export default {
async fetch(request, env, ctx) {
const client = new ImapFlow({
host: 'imap.example.com',
port: 993,
secure: true,
auth: { user: 'user@example.com', pass: 'password' },
logger: false,
transport: createSocketsTransport(connect)
});
await client.connect();
const status = await client.status('INBOX', { messages: true });
await client.logout();
return Response.json(status);
}
};
Implicit TLS, STARTTLS, cleartext, IDLE, download() and the default Pino logger work. Compared with Node.js:
- The server certificate is always verified against the runtime's root store.
tls.rejectUnauthorized: false, a customtls.ca, client certificates and aservernamethat differs fromhostare refused withUnsupportedTransportOption, and a TLS connection to an IP address needs a certificate issued for that address. - COMPRESS=DEFLATE is skipped, the runtime has no streaming zlib.
- The
proxyoption can not be combined with a transport. client.tlsstaysfalse, the runtime reports no cipher details.- A socket is closed when the request (or Durable Object event) that opened it ends. Run the whole session inside the handler, or inside
ctx.waitUntil()to keep it going after the response. A connection can not be kept open between requests.
Browsers
ImapFlow runs in a browser from the ES module build, bundled together with replacements for the Node.js modules it imports. Browsers have no sockets, so the connection comes from a custom transport: a socket API such as Chrome's Direct Sockets (Isolated Web Apps only), a WebSocket relay to a TCP proxy, or an in-memory connection. Regular browser extensions have no raw TCP access.
The bundler has to provide:
node:streamfrom readable-stream,node:eventsfrom events, and theBufferglobal from buffer- the
processglobal from process, andsetImmediate()andclearImmediate()globals node:cryptowith an MD5createHash(), used for message ids on servers without OBJECTID, andpathwithparse(), used by a dependency for attachment file names- empty modules for
node:net,node:tls,node:dnsandnode:zlib, which makes ImapFlow skip COMPRESS
The ImapFlow repository has a complete esbuild setup with the shims in test/browser/, which runs a full session in headless Chrome.
Upgrading from ImapFlow 1.x
ImapFlow 2.0 is the TypeScript rewrite of the library. The API is unchanged, but a few packaging details are different:
- Node.js 20 or newer is required.
- The
lib/directory is no longer published. Load the package from its root as shown above. A deep import such asimapflow/lib/toolskeeps resolving through the package's export map, but only the root entry is a supported API. - The hand-written declaration file is replaced by declarations generated from the source. Internal members of the client are no longer visible to TypeScript, and every optional property is declared as accepting
undefined.
Verify Installation
After installation, verify that ImapFlow is installed correctly:
npm list imapflow
You should see the installed version of ImapFlow in the output.
Next Steps
Now that you have ImapFlow installed, you can:
- Learn the Basic Usage
- Explore Configuration Options
- Check out Code Examples