ImapFlow

website·Indexed 32 days ago

https://imapflow.com

A modern IMAP client library for Node.js featuring a full Promise and async/await API. It provides tools for connecting to IMAP servers, managing mailboxes, searching for messages, and fetching email content.

Tokens
19.3K
Snippets
104
Records
120
Agent score
68%

What's inside ImapFlow

  1. Overview of ImapFlow fetch methods

    ImapFlow provides several methods to retrieve messages depending on whether you need a stream, a full list, or a single message:

    • fetch(): Returns an async iterator for streaming multiple messages.
    • fetchAll(): Fetches all requested messages and returns them as an array.
    • fetchOne(): Fetches a single message and returns it directly.
    • download(): Downloads a specific message part as a stream.
    • downloadMany(): Downloads multiple message parts simultaneously.
  2. Overview of ImapFlow IMAP Client

    ImapFlow is a production-ready IMAP client built for modern Node.js. It provides a clean, intuitive API with full Promise and async/await support. Key capabilities include message fetching, searching, mailbox management, automatic handling of IMAP extensions, and built-in TypeScript definitions. It is designed for reliable connection management, error handling, and proxy support.
  3. Understand the QuotaResponse object properties

    The QuotaResponse object provides information about mailbox quotas. It includes:

    • path (String): Mailbox path the quota applies to
    • quotaRoot (String): Quota root reported by the server, if any
    • storage (Object): The STORAGE resource (usage and limit in bytes, status as usage percentage, e.g., "50%")
    • message (Object): The MESSAGE resource (usage and limit as message counts, status as usage percentage)

    Additional resources reported by the server (e.g., the mailbox resource from RFC 9208) are added under their lowercased name with usage, limit, and status fields. usage or limit are omitted if the server did not provide a usable number, and status is only set if a limit above zero is known.

  4. Access ImapFlow client properties

    The ImapFlow client provides several properties to check the current state of the connection and the active mailbox:

    • mailbox: Contains information about the currently selected mailbox (e.g., path, exists, uidValidity, uidNext, flags, readOnly). Accessing this should typically be done while holding a mailbox lock.
    • authenticated: The authenticated username, false if not authenticated, or true if pre-authenticated by the server.
    • secureConnection: Boolean indicating if the connection is encrypted.
    • usable: Boolean indicating if the client is both connected and authenticated.
    • capabilities: A Map<string, boolean | number> of server capabilities.
    • enabled: A Set<string> of activated IMAP extensions (e.g., IMAP4REV2).
    • host / port: The connection destination.
    • idling: Boolean indicating if the client is currently in IDLE mode.
    let lock = await client.getMailboxLock('INBOX');
    try {
        console.log('Path:', client.mailbox.path);
        console.log('Messages:', client.mailbox.exists);
        console.log('Read-only:', client.mailbox.readOnly);
    } finally {
        lock.release();
    }
  5. Get mailbox status without selecting it

    The status(path, query) method retrieves specific metadata about a mailbox without requiring it to be selected first. The query object allows you to request: messages (total count), recent (recent count), uidNext (next UID), uidValidity, unseen (unseen count), highestModseq, size (total size in octets), and deleted (count of messages with \Deleted flag).
    let status = await client.status('INBOX', {
        messages: true,
        unseen: true,
        highestModseq: true,
        size: true
    });
    console.log(`${status.unseen}/${status.messages} unseen`);
    if (typeof status.size === 'number') {
        console.log(`Mailbox size: ${status.size} bytes`);
    }
  6. Retrieve mailbox metadata

    When a mailbox is locked, the client.mailbox property provides metadata about the currently selected mailbox, including the path, message count, and UID validity.
    let lock = await client.getMailboxLock('INBOX');
    try {
        console.log('Path:', client.mailbox.path);
        console.log('Total messages:', client.mailbox.exists);
        console.log('UID of next message:', client.mailbox.uidNext);
        console.log('UIDVALIDITY:', client.mailbox.uidValidity);
        console.log('Highest modseq:', client.mailbox.highestModseq);
        console.log('Read-only mode:', client.mailbox.readOnly);
        console.log('Permanent flags:', client.mailbox.permanentFlags);
    } finally {
        lock.release();
    }
  7. Create, rename, and delete mailboxes

    ImapFlow provides methods to manage mailbox lifecycles. mailboxCreate can take a string path or an array of segments (which are joined using the server's delimiter). mailboxRename changes the name of an existing mailbox, and mailboxDelete removes a mailbox and all its messages.
    // Create a single mailbox
    await client.mailboxCreate('Projects/2024');
    
    // Create nested mailboxes (joined by server delimiter)
    await client.mailboxCreate(['Work', 'Projects', 'ImapFlow']);
    
    // Rename a mailbox
    let renameResult = await client.mailboxRename('Old Name', 'New Name');
    
    // Delete a mailbox (Warning: deletes all messages)
    await client.mailboxDelete('Temporary');
  8. Manage mailbox subscriptions

    Use mailboxSubscribe to subscribe to a mailbox and mailboxUnsubscribe to remove a subscription. To list only subscribed mailboxes, filter the results of client.list() by the subscribed property.
    // Subscribe/Unsubscribe
    await client.mailboxSubscribe('Important');
    await client.mailboxUnsubscribe('Old Projects');
    
    // List only subscribed
    let subscribed = await client.list();
    let subscribedOnly = subscribed.filter(m => m.subscribed);
  9. Select and lock a mailbox for operations

    Before reading or manipulating messages, you must select a mailbox and acquire a lock using getMailboxLock(name). This lock must be released in a finally block to prevent resource leaks. Once locked, you can access mailbox metadata via client.mailbox (e.g., client.mailbox.exists).
    let lock = await client.getMailboxLock('INBOX');
    try {
        console.log('Messages in INBOX:', client.mailbox.exists);
        // Perform operations here
    } finally {
        lock.release();
    }
  10. Watch for new messages in real-time

    To receive real-time notifications of new messages, listen for the exists event on the client. This event fires when the number of messages in the mailbox changes. Because the EventEmitter in Node.js does not await async handlers, you must wrap logic inside async event handlers with a try/catch block to handle errors.
    async function watchAndFetch() {
        await client.connect();
        let lock = await client.getMailboxLock('INBOX');
        try {
            let lastCount = client.mailbox.exists;
    
            client.on('exists', async (data) => {
                try {
                    if (data.count > lastCount) {
                        // Fetch messages from the last known count to the end
                        let newMessages = await client.fetchAll(
                            `${lastCount + 1}:*`,
                            { envelope: true }
                        );
                        for (let msg of newMessages) {
                            console.log(`New: ${msg.envelope.subject}`);
                        }
                        lastCount = data.count;
                    }
                } catch (err) {
                    console.error('Error fetching new message:', err);
                }
            });
    
            await new Promise(resolve => process.on('SIGINT', resolve));
        } finally {
            lock.release();
        }
        await client.logout();
    }
  11. Upgrade from ImapFlow 1.x to 2.0

    ImapFlow 2.0 is a TypeScript rewrite. While the API remains unchanged, the following changes apply:

    • Node.js 20 or newer is now required.
    • The lib/ directory is no longer published. All imports should be made from the package root.
    • Type declarations are now generated from source; internal client members are no longer visible to TypeScript, and optional properties now explicitly accept undefined.
  12. Safely access mailboxes using Mailbox Locks

    ImapFlow uses a locking mechanism to prevent race conditions where different parts of the code might switch mailboxes concurrently. Use getMailboxLock(mailboxName) to ensure the mailbox remains selected during your operations. Always release the lock in a finally block to avoid deadlocks.
    let lock = await client.getMailboxLock('INBOX');
    try {
        // The mailbox remains selected and locked
        console.log(`${client.mailbox.exists} messages`);
        let message = await client.fetchOne('*', { envelope: true });
    } finally {
        // Always release the lock
        lock.release();
    }