/install imapflow
\r \r
ImapFlow\r
\r
Overview\r
\r ImapFlow is a modern, promise-based IMAP client for Node.js. It auto-detects and handles IMAP extensions (CONDSTORE, QRESYNC, IDLE, COMPRESS, etc.) so the same code works across servers.\r \r Key features: async/await API, async iterators for message streaming, built-in mailbox locking, TypeScript support, SOCKS/HTTP proxy support, Gmail X-GM-EXT-1 support.\r \r
Trigger Scene\r
\r Use when building email features: connecting to IMAP servers, fetching/reading emails, searching mailboxes, managing folders, monitoring new messages via IDLE, working with Gmail labels and Gmail-specific extensions, or any IMAP-based email automation. \r \r
Quick Start\r
\r
const { ImapFlow } = require('imapflow');\r
\r
const client = new ImapFlow({\r
host: 'imap.example.com',\r
port: 993,\r
secure: true,\r
auth: { user: '[email protected]', pass: 'password' }\r
});\r
\r
await client.connect();\r
\r
let lock = await client.getMailboxLock('INBOX');\r
try {\r
// Fetch latest message\r
let msg = await client.fetchOne(client.mailbox.exists, { source: true });\r
console.log(msg.source.toString());\r
\r
// Stream all messages\r
for await (let msg of client.fetch('1:*', { envelope: true })) {\r
console.log(`${msg.uid}: ${msg.envelope.subject}`);\r
}\r
} finally {\r
lock.release();\r
}\r
\r
await client.logout();\r
```\r
\r
## Core Tasks\r
\r
### 1. Connecting\r
\r
```js\r
const client = new ImapFlow({\r
host: 'imap.example.com',\r
port: 993,\r
secure: true,\r
auth: { user: '[email protected]', pass: 'password' }\r
});\r
await client.connect();\r
```\r
\r
**Provider-specific configs** → See [references/connection.md](references/connection.md) for Gmail, Outlook, Yahoo, iCloud, and other common providers.\r
\r
**OAuth2 / XOAUTH2:**\r
```js\r
auth: {\r
user: '[email protected]',\r
accessToken: 'ya29.xxx...'\r
}\r
```\r
\r
**Common options:**\r
- `logger`: Pass a logger object (`console`, pino, etc.) for debug output. Set `logger: false` to disable.\r
- `emitLogs`: Set `true` to emit 'log' events instead of using a logger.\r
- `clientInfo`: Custom client identification `{ name: 'myapp', version: '1.0.0' }`.\r
- `disableAutoIdle`: Disable automatic IDLE when mailbox is selected.\r
\r
**Disconnect:** Call `client.logout()` for graceful disconnect. Handle `client.close()` for abrupt close.\r
\r
### 2. Fetching Messages\r
\r
**Always acquire a mailbox lock before fetching:**\r
```js\r
let lock = await client.getMailboxLock('INBOX');\r
try {\r
// ... fetch operations ...\r
} finally {\r
lock.release();\r
}\r
```\r
\r
**Fetch one message:**\r
```js\r
let msg = await client.fetchOne('*', { source: true });\r
// or by sequence number: client.fetchOne(42, { source: true })\r
// or by UID (append `uid` flag):\r
let msg = await client.fetchOne('12345', { uid: true, source: true });\r
```\r
\r
**Fetch query options** (what data to retrieve — choose only what you need):\r
- `source` — Full RFC822 message source (as Buffer)\r
- `envelope` — Parsed envelope (subject, from, to, date, message-id)\r
- `bodyStructure` — MIME structure tree\r
- `flags` — Array of flags (\\Seen, \\Answered, etc.)\r
- `internalDate` — Internal server date\r
- `size` — Message size in bytes\r
- `uid` — UID (always included)\r
- `threadId` — THREAD=ORDEREDSUBJECT reference (Gmail)\r
- `labels` — Gmail labels (X-GM-LABELS)\r
- `headers` — Raw headers as Buffer\r
- `bodyParts` — Array of MIME part paths to fetch, e.g. `['1.1', '1.2']`\r
\r
**Stream/iterate messages:**\r
```js\r
// Range: sequence numbers\r
for await (let msg of client.fetch('1:100', { envelope: true, flags: true })) {\r
console.log(`${msg.seq}: ${msg.envelope.subject}`);\r
}\r
\r
// All messages: '1:*'\r
for await (let msg of client.fetch('1:*', { envelope: true })) { /* ... */ }\r
\r
// By UID range\r
for await (let msg of client.fetch('1000:2000', { uid: true, envelope: true })) { /* ... */ }\r
```\r
\r
**Fetch specific body parts:**\r
```js\r
let msg = await client.fetchOne('*', {\r
bodyParts: ['1.1', '1.2'], // MIME part paths\r
source: true\r
});\r
// msg.bodyParts.get('1.1') → Buffer\r
// msg.text.toString() → decoded text content\r
```\r
\r
**Download attachments:**\r
```js\r
let msg = await client.fetchOne('*', { source: true, bodyStructure: true });\r
for (let attachment of msg.attachments) {\r
let buf = await client.download(msg.uid, attachment.part, { uid: true });\r
// buf contains the attachment data\r
}\r
```\r
\r
**Common envelope fields:** `msg.envelope.subject`, `msg.envelope.from[0].address`, `msg.envelope.to[0].address`, `msg.envelope.date`, `msg.envelope.messageId`, `msg.envelope.inReplyTo`.\r
\r
### 3. Searching\r
\r
```js\r
let lock = await client.getMailboxLock('INBOX');\r
try {\r
// Simple search\r
let list = await client.search({ unseen: true });\r
\r
// Complex query\r
let list = await client.search({\r
from: '[email protected]',\r
subject: 'invoice',\r
seen: false,\r
since: new Date('2024-01-01'),\r
before: new Date('2024-12-31'),\r
larger: 1024 * 1024 // > 1MB\r
});\r
\r
// Text search (body)\r
let list = await client.search({ body: 'important keyword' });\r
\r
// Combine with OR\r
let list = await client.search({\r
or: [\r
{ from: '[email protected]' },\r
{ from: '[email protected]' }\r
]\r
});\r
\r
// Combine AND + OR\r
let list = await client.search({\r
subject: 'report',\r
or: [\r
{ from: '[email protected]' },\r
{ from: '[email protected]' }\r
]\r
});\r
\r
// List is an array of sequence numbers. Use fetch() with those:\r
for await (let msg of client.fetch(list, { envelope: true })) {\r
console.log(msg.envelope.subject);\r
}\r
} finally {\r
lock.release();\r
}\r
```\r
\r
**Search keys** → See [references/searching.md](references/searching.md) for the full IMAP search key reference.\r
\r
**Gmail raw search (X-GM-RAW):**\r
```js\r
let list = await client.search({ 'x-gm-raw': 'has:attachment larger:10M' });\r
```\r
\r
### 4. Mailbox Management\r
\r
```js\r
// List all mailboxes\r
let mailboxes = await client.list();\r
for (let mb of mailboxes) {\r
console.log(`${mb.name} (${mb.path})`);\r
}\r
// Filter by pattern: client.list({ path: 'INBOX/*' })\r
\r
// Status (message count, unseen, etc.)\r
let status = await client.status('INBOX', { messages: true, unseen: true, uidNext: true });\r
console.log(`${status.messages} total, ${status.unseen} unseen`);\r
\r
// Mailbox info (when a mailbox is selected)\r
console.log(client.mailbox.exists); // total messages\r
console.log(client.mailbox.uidNext); // next predicted UID (CONDSTORE)\r
console.log(client.mailbox.uidValidity);\r
\r
// Create / Rename / Delete\r
await client.mailboxCreate('Projects/NewProject');\r
await client.mailboxRename('Projects/Old', 'Projects/New');\r
await client.mailboxDelete('Projects/Archive');\r
\r
// Subscribe / Unsubscribe\r
await client.mailboxSubscribe('INBOX/Newsletters');\r
await client.mailboxUnsubscribe('INBOX/Newsletters');\r
\r
// Move messages\r
await client.messageMove('1:5', 'Archive', { uid: false });\r
// Copy messages\r
await client.messageCopy('100:200', 'Important', { uid: true });\r
\r
// Delete messages (set \Deleted flag + expunge)\r
await client.messageDelete('1:10');\r
// Or manually: flag + expunge\r
await client.messageFlagsAdd('1:10', ['\\Deleted']);\r
await client.messageExpunge('1:10'); // or expunge all: client.mailboxExpunge()\r
```\r
\r
### 5. IDLE (Push Notifications)\r
\r
ImapFlow automatically enters IDLE when there's an active mailbox lock and no pending commands. Use events to react to new messages:\r
\r
```js\r
client.on('exists', async (data) => {\r
console.log(`New messages! Count: ${data.count}`);\r
// Fetch new messages\r
let lock = await client.getMailboxLock('INBOX');\r
try {\r
for await (let msg of client.fetch(`${data.prevCount + 1}:${data.count}`, { envelope: true })) {\r
console.log(`New: ${msg.envelope.subject}`);\r
}\r
} finally {\r
lock.release();\r
}\r
});\r
\r
client.on('expunge', (data) => {\r
console.log(`Message seq#${data.seq} was deleted`);\r
});\r
\r
client.on('flags', (data) => {\r
console.log(`Flags changed for seq#${data.seq}: ${data.flags}`);\r
});\r
\r
// Connect and select mailbox — IDLE starts automatically\r
await client.connect();\r
let lock = await client.getMailboxLock('INBOX');\r
// Keep lock active — IDLE runs in background\r
```\r
\r
**Manual IDLE control:**\r
```js\r
client.on('idle', () => console.log('Entered IDLE'));\r
// To disable auto-IDLE: new ImapFlow({ disableAutoIdle: true })\r
```\r
\r
### 6. Gmail-Specific Operations\r
\r
```js\r
// Gmail labels\r
let msg = await client.fetchOne('*', { labels: true });\r
console.log(msg.labels); // ['\\Inbox', 'Important', 'Starred']\r
\r
// Set labels\r
await client.messageFlagsAdd('1', ['\\Starred', 'Important'], { uid: true });\r
await client.messageFlagsRemove('100', ['Important'], { uid: true });\r
await client.messageFlagsSet('42', ['\\Inbox', 'CustomLabel'], { uid: true });\r
\r
// Gmail raw search\r
let results = await client.search({ 'x-gm-raw': 'from:alice has:attachment newer_than:7d' });\r
\r
// Gmail thread ID\r
let msg = await client.fetchOne('*', { threadId: true });\r
console.log(msg.threadId); // Gmail thread identifier\r
```\r
\r
Gmail connection config:\r
```js\r
new ImapFlow({\r
host: 'imap.gmail.com',\r
port: 993,\r
secure: true,\r
auth: {\r
user: '[email protected]',\r
accessToken: 'oauth2-token' // Use OAuth2\r
}\r
})\r
```\r
\r
> **Note:** Gmail requires OAuth2 or App Passwords. Regular passwords won't work unless "Less secure app access" is enabled (deprecated).\r
\r
### 7. Error Handling & Reconnection\r
\r
**Connection events:**\r
```js\r
client.on('error', (err) => {\r
console.error('IMAP error:', err.message);\r
// Connection is likely closed after a fatal error\r
});\r
\r
client.on('close', () => {\r
console.log('Connection closed');\r
// Reconnect logic here\r
});\r
\r
client.on('connectionError', (err) => {\r
console.error('Connection failed:', err.message);\r
});\r
```\r
\r
**Reconnection pattern:**\r
```js\r
async function connectWithRetry(config, maxRetries = 5) {\r
for (let i = 0; i \x3C maxRetries; i++) {\r
try {\r
const client = new ImapFlow(config);\r
await client.connect();\r
return client;\r
} catch (err) {\r
console.error(`Connection attempt ${i + 1} failed: ${err.message}`);\r
if (i \x3C maxRetries - 1) {\r
await new Promise(r => setTimeout(r, Math.min(1000 * Math.pow(2, i), 30000)));\r
}\r
}\r
}\r
throw new Error('All connection attempts failed');\r
}\r
```\r
\r
**Mailbox locking best practices:**\r
- Always use `try/finally` to release locks\r
- Keep lock durations short — release between operations when possible\r
- Never hold a lock across network calls or long async operations\r
- Use separate locks for read vs write operations when safe\r
\r
```js\r
// BAD: lock held too long\r
let lock = await client.getMailboxLock('INBOX');\r
let results = await client.search({ unseen: true });\r
// ... process results (slow, lock held) ...\r
lock.release();\r
\r
// GOOD: release lock between operations\r
let results;\r
{\r
let lock = await client.getMailboxLock('INBOX');\r
results = await client.search({ unseen: true });\r
lock.release();\r
}\r
// Process results without holding lock\r
for (let seq of results) { /* ... */ }\r
```\r
\r
**Timeouts and connection health:**\r
```js\r
// No operation timeout (blocks forever) — set one\r
const timeout = setTimeout(() => client.close(), 30000);\r
// ... your operation ...\r
clearTimeout(timeout);\r
\r
// Check if connected: client.usable → true/false\r
```\r
\r
## Reference Files\r
\r
- **[connection.md](references/connection.md)** — Provider-specific connection configs: Gmail, Outlook/Hotmail, Yahoo, iCloud, Zoho, Fastmail, custom servers. Includes TLS, OAuth2, App Passwords, and proxy setup.\r
- **[searching.md](references/searching.md)** — Complete IMAP search key reference: flags, dates, sizes, headers, text searches, logical operators, sequence sets, Gmail raw search.\r
- **[api_reference.md](references/api_reference.md)** — Key API methods summary: client methods, events, MailboxLock, FetchQueryObject options, and ImapFlow constructor options.
- Make sure OpenClaw is installed (local or Docker)
- Run the install command in chat:
/install imapflow - After installation, invoke the skill by name or use
/imapflow - Provide required inputs per the skill's parameter spec and get structured output
What is imapflow?
Modern Node.js IMAP client library (imapflow) for email integration.Covers authentication, mailbox locking, streaming fetches, async iterators, reconnection... It is an AI Agent Skill for Claude Code / OpenClaw, with 8 downloads so far.
How do I install imapflow?
Run "/install imapflow" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.
Is imapflow free?
Yes, imapflow is completely free, licensed under MIT-0. You can download, install and use it at no cost.
Which platforms does imapflow support?
imapflow is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).
Who created imapflow?
It is built and maintained by OpenLark (@openlark); the current version is v1.0.0.