Interacting with a mailbox in Node.js with ImapFlow and MailParser
NicolasBrondinBernard
Discover how to read and process emails from a mailbox in Node.js with ImapFlow and MailParser, using IMAP to retrieve messages.

Article published on 15/06/2026, last updated on 10/08/2026
Sending emails with Node.js is very simple with tools like Nodemailer!
Our dedicated article for sending emails in Node.js
But there are also many cases where you want to do the opposite: read received emails.
For example, to automatically process incoming requests, retrieve attachments, analyze customer replies, or trigger an action when a message arrives in a specific mailbox.
For this, we generally use a dedicated protocol: IMAP (Internet Message Access Protocol).
IMAP allows an application to connect to a mailbox to read, browse, and manipulate messages.
In Node.js, two libraries are particularly handy for this need: ImapFlow and MailParser.
ImapFlow is a modern IMAP client for Node.js, with an API based on Promises and async/await (official documentation).
MailParser, on the other hand, lets you transform a raw email into a usable JavaScript object. Its simpleParser function is handy for simple cases, while the MailParser class allows you to process large messages as streams (official documentation).
How it works
Installing the dependencies
We start by installing the two packages:
npm install imapflow mailparser
If you're using TypeScript, ImapFlow already provides its own types. For MailParser, you can add:
npm install -D @types/mailparser
Connecting to a mailbox
Here's an example with Gmail, but the principle is the same with any IMAP server.
import { ImapFlow } from "imapflow";
const client = new ImapFlow({
host: "imap.gmail.com",
port: 993,
secure: true,
auth: {
user: "votre-adresse@gmail.com",
pass: "votre-app-password",
},
});
await client.connect();
For Gmail, you shouldn't use your main password.
You need to generate an App Password from your Google account, then use it as the IMAP password.
Reading the latest emails
Once connected, you need to open a mailbox. The most common one is INBOX.
const lock = await client.getMailboxLock("INBOX");
try {
for await (const message of client.fetch("1:*", {
envelope: true,
source: true,
})) {
console.log(message.envelope.subject);
}
} finally {
lock.release();
}
The lock prevents multiple operations from conflicting on the same mailbox.
This is a good habit with ImapFlow: you lock, you work, then you release.
Here, source: true allows us to retrieve the raw email. This is the content we're going to pass to MailParser next.
Parsing an email with MailParser
An email isn't just plain text. It can contain HTML, plain text, attachments, different encodings, headers, recipients, etc.
MailParser takes care of turning all of this into an object that's easier to work with:
import { simpleParser } from "mailparser";
for await (const message of client.fetch("1:*", {
envelope: true,
source: true,
})) {
const parsed = await simpleParser(message.source);
console.log({
subject: parsed.subject,
from: parsed.from?.text,
text: parsed.text,
html: parsed.html,
});
}
simpleParserloads the message into memory.
This is very handy to get started, but if you're dealing with large emails or lots of attachments, you'll want to use MailParser's streaming API instead.
Reading only unread emails
In real life, you don't want to re-read the entire mailbox on every run.
You can search for unread emails only:
for await (const message of client.fetch(
{ seen: false },
{ envelope: true, source: true }
)) {
const parsed = await simpleParser(message.source);
console.log(parsed.subject);
}
Then, you can mark the message as read:
await client.messageFlagsAdd(message.uid, ["\\Seen"], { uid: true });
This makes it easy to build a small worker that only processes new emails.
Complete example
import { ImapFlow } from "imapflow";
import { simpleParser } from "mailparser";
const client = new ImapFlow({
host: "imap.gmail.com",
port: 993,
secure: true,
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASSWORD,
},
});
await client.connect();
const lock = await client.getMailboxLock("INBOX");
try {
for await (const message of client.fetch(
{ seen: false },
{ uid: true, source: true }
)) {
const parsed = await simpleParser(message.source);
console.log("Sujet :", parsed.subject);
console.log("De :", parsed.from?.text);
console.log("Texte :", parsed.text);
await client.messageFlagsAdd(message.uid, ["\\Seen"], { uid: true });
}
} finally {
lock.release();
await client.logout();
}
Complete courses, exercises and certificates to really learn programming!
4.8 average rating
No comments yet