Search code examples
node.jsimapflow

How to get plan & html body of email in ImapFlow?


As I understand, I have to use client.download for each email, like:

const { content } = await client.download(message.uid, ['1', '2']);

But code just hangs on this line.

My current code is:

const client = new ImapFlow({
    host: 'imap.server.com',
    port: 993,
    secure: true,
    auth: {
        user: '', // Replace with your email address
        pass: '' // Replace with your password
    },
    logger: {
        level: 'info' // Set logging level as per your preference
    }
});

try {
    await client.connect();
    const lock = await client.getMailboxLock('INBOX');

    for await (const message of client.fetch('1:*', { envelope: true, bodyParts: true,
        bodyStructure: true })) {
        //console.log(message);
        console.log(message.bodyStructure.childNodes);
        //console.log(message.envelope);
    }

    lock.release();
} catch (err) {
    console.error('Error:', err);
} finally {
    await client.logout();
}

Solution

  • replied to you in Github (Imapflow library) but here is what I did in a Typescript Class:

    After

    npm i mailparser @types/mailparser
    

    First, Initiate your client, then fetch once your emails with

    const mailboxName = 'INBOX';
    const lock = await client.getMailboxLock(mailboxName);
    let messages = [];
    for await (const msg of client.fetch('1:*', {
        flags: true,
        envelope: true,
        source: false,
        bodyStructure: true,
        uid: true,
    })) {
        if (msg) {
            msg['mailbox'] = mailboxName;
            messages.push(msg);
        }
    }
    lock.release();
    

    Then do whatever filtering you want on your messages list and use it (with your client also) in fetchMessagesBody function (place debug endpoints it will help)

    import { ShopEntityWithConnector } from './email.controller';
    import { ParsedMail, simpleParser } from 'mailparser';
    
    export class MyEmailClass {
        concat_RS = (stream) => new Promise((res, rej) => {
            var buffers = [];
            stream.on("data", function (data) { buffers.push(data); });
            stream.on("end", function () { res(Buffer.concat(buffers)); });
        });
    
      async fetchMessagesBody(client: ImapFlow, messages: FetchMessageObject[]) {
        let mailbox = await client.getMailboxLock('INBOX');
        let fullMessages: { uid: number, source: ParsedMail, text: string }[] = [];
    
        for (let message of messages) {
    
          let { meta, content } = await client.download(message.seq.toString());
          const buf = await this.concat_RS(content);
          const contentString = buf.toString();
          const parsedMail: ParsedMail = await simpleParser(content);
          fullMessages.push({ uid: message.uid, source: parsedMail, text: contentString });
        }
        mailbox.release();
        return fullMessages;
    
      }
    }
    

    I tried to fetch only HTML part, quite buggy, I prefer downloading the whole email and delete attachment or store in DB then Query if I want to speed-up things