npm / imapflow
imapflow
What changed in imapflow 1 to 2, from its official release notes, upgrade guides and advisories. Sources checked 2026-10-18.
14 breaking13 security15 new APIs and options2 behavior and defaults104 fixes and other
See which of these apply to your code, ranked, in your agent:
npx @unstale/cli initimapflow 277 changes
Breaking changes 12
A tagged BYE no longer passes as success.
ImapSocket is now an alias of ImapTransportSocket rather than net.Socket; TypeScript code using net.Socket-only members needs a cast.
Commands now fail on a NO or BAD status line without a tag.
Drops flags and keywords that are not atoms rather than sending them quoted.
Unknown search keys are refused instead of being accepted.
A NUL in a non-ASCII search value is rejected instead of being sent as a literal.
Search refuses empty operands.
Throttle, truncation and listener failures are surfaced instead of hidden, so callers can detect them.
The declarations no longer expose ImapFlow's internal members.
The export map provides a supported path for accessing library modules now that the lib/ directory is no longer published.
The lib/ directory is no longer published; use the package root or the imapflow/lib/* export map instead.
Node.js 20 or newer is now required to use imapflow.
Security 2
Limits what a hostile server can make the client buffer or wait for.
Response parsing and command compilation were hardened after issues were found by fuzzing.
New APIs and options 10
Added createSocketsTransport() for celld.
Added createStreamsTransport() for socket APIs built on web streams.
A transport option was added for celld.
Unexpected parser exceptions are re-raised as coded ParserErrorInternal errors.
An alert event is emitted for ALERT response codes, allowing applications to handle these server alerts.
The client can choose the hash used behind the fallback message id.
Exports ImapFlowErrorCode with the error codes set by the library.
Supports await using through Symbol.asyncDispose.
Bun and Cloudflare Workers are now supported runtimes.
The package now provides ES module and CommonJS builds.
Behavior and default changes 1
A warning is issued when STARTTLS falls back to cleartext, making the fallback visible to developers.
Fixes and other changes 52
The ID command is sent after STARTTLS instead of before it.
Download decoding handles padded base64 parts in linear memory.
Append literals are kept in sync with their data.
Downloads fail cleanly.
The first chunk of a download is requested again when the answer comes back empty.
A throttled login is no longer treated as a rejected credential.
An empty response for a download chunk causes the chunk to be requested again instead of failing the download.
Reads NAMESPACE prefixes, QUOTAROOT names, and ID values when the server sends them as literals.
fetchOne() takes the requested message when a FETCH answer also carries unsolicited rows.
Socket errors after a failed STARTTLS upgrade are logged instead of thrown on Bun.
Declares DownloadOptions.binary so TypeScript users can use the option with its type recognized.
Declares the QRESYNC mailboxOpen options in the type definitions.
Refetches body sections that Apache James drops.
Enables CONDSTORE with QRESYNC.
Checks that FETCH answers belong to the download.
Expands FETCH ALL, FAST, and FULL macros instead of sending them in a list.
Encodes and decodes non-ASCII Gmail labels as modified UTF-7, like mailbox names.
Decrements mailbox.exists when the server sends an untagged VANISHED response, keeping the mailbox count consistent.
Sends the OAuth token after the continuation request when SASL-IR is not advertised.
Does not send sequence sets when the mailbox is empty.
Sends the UNCHANGEDSINCE modifier before the flags.
Leaves servername out of tls.connect() for IP literal hosts, which Bun rejects.
downloadMany now enforces maxBytes, preventing downloads from exceeding the configured byte limit.
A lost login is reported only once.
The transport is closed when a connection attempt fails.
Digit-led atoms such as "2024:Q1" are read instead of causing the response line to be dropped.
Non-ASCII search values are sent as literals, addressing issue #417.
Append flags are kept when the destination is not an open read-write mailbox.
A flag update that reduces to nothing no longer clears every flag.
IMAP4rev2 is no longer enabled on Strato RZimapd, avoiding the issue with that server.
Closing settles every pending connect operation.
NIL envelope rows are kept.
Top-level special-use folders are preferred.
Reads the last extension field of a BODYSTRUCTURE part.
Rejects connect() immediately when the server sends a BYE greeting.
Processes a chunk that arrives while the input loop is winding down.
Parses a chunk containing many literals in a loop instead of recursing.
Preserves a bracketed IPv6 host in a REFERRAL URL.
When the best special-use candidate is taken, its next candidate is given a special-use type.
QRESYNC accepts uidValidity as either a number or a string.
Keeps auto-IDLE disabled on a socket handed over by unbind().
The quota response type now describes the value returned by getQuota().
The source is no longer expunged when the fallback COPY fails, preventing message loss.
Body sections sent by the server as quoted strings are now kept as quoted strings.
The parser now splits flags when a server writes them without the separating space.
The chunked download loop is bounded by the reported message size.
Chunked downloads stop when the server ignores the partial spec.
Skip LSUB after a server rejects ENABLE over the IMAP4rev2 it advertises.
Imapflow stops acting on an IMAP4rev2 advertisement after the server rejects ENABLE over it.
AuthenticationFailure.response is now typed as a string, matching its actual value.
Auto-IDLE is re-armed after an IDLE or poll session ends on its own.
Events are typed without relying on the generic EventEmitter from @types/node.
imapflow 171 changes
Breaking changes 2
Non-secure connections now default to IMAP port 143 instead of POP3 port 110.
close() now rejects synchronously instead of using setImmediate.
Security 11
Credential frames are masked in the raw log while error detail is preserved.
Parsing of untrusted server response values was hardened.
Blocks IMAP command injection.
Hardens rev2 protocol handling.
Response parsing, tag correlation, IDLE polling, and proxy connection setup are hardened.
The FLAGS guard was hardened; the notes do not specify the affected behavior.
Connection error paths were hardened.
Literal bounds handling was hardened.
The STARTTLS upgrade path was hardened.
Hardens the parser.
Hardened mailbox-lock and error-propagation paths.
New APIs and options 5
The auto-IDLE delay is configurable through autoIdleDelay.
Adds rev2 BINARY fetch support.
Adds support for STATUS SIZE/DELETED.
The search compiler supports a Gmail label search term.
Adds ESEARCH (RFC 4731) and PARTIAL (RFC 9394) support.
Behavior and default changes 1
Special-use folder names are expanded from client localization catalogs, allowing localized names to be recognized.
Fixes and other changes 52
Keeps the pipeline error forwarder across a backpressure wait, preventing errors from being lost.
A re-stamped rejection no longer carries the previous site's markers.
An IDLE-break waiter now has its own rejection site.
Search dates are normalized so invalid values cannot throw or emit NaN.
Connection errors are stamped, and the rejection guard is structural, making connection-error handling more consistent.
The IDLE preCheck waiter is guarded, and connection errors name the rejection site.
The type now accepts string[] paths.
The type now accepts string[] paths.
Envelope parsing no longer invents an address when the host field is NIL.
The type now accepts string[] paths.
The type now accepts string[] paths.
The type now accepts string[] paths.
Auto-IDLE is kept off a busy connection.
The socket watchdog is aligned with the auto-IDLE busy guard.
Folders are assumed to be subscribed when the server reports no subscription state.
IMAP4rev2 sessions no longer fall back to LSUB.
Authentication results are now kept on a verifyOnly connection.
Missing localized special-use folder names are added, and names are normalized to NFC.
Decorated folder names are matched, and special-use names are normalized to NFKC.
The types now declare specialUseHints.archive.
The types now declare specialUseSource.
Fixes protocol bugs found in an RFC 9051 review.
The list operation requests subscription state inline and supports IMAP4rev2.
Folder handling now passes the StatusObject value instead of its boolean primitive.
The OAUTHBEARER payload now describes the real connection.
Mailboxes marked \NonExistent in LIST responses are treated as \Noselect.
Corrects flag removal behavior.
Prevents host process crashes caused by socket errors after unbind() when COMPRESS=DEFLATE is active.
Corrects literal parsing.
Corrects path normalization.
Handles THREADID NIL in FETCH responses.
Handles a NIL delimiter in NAMESPACE responses, as specified by RFC 2342.
Handles the plain Array form for PARTIAL in the ESEARCH parser.
Corrects the return type of ESEARCH search().
Compound OR/NOT search conditions are parenthesized according to RFC 3501.
Corrects handling of red at index 0, which was treated as falsy.
Matches euc-jp in decoder selection.
Uses nullish coalescing when resolving flag colors.
Uses nullish coalescing in charset resolution.
Handles BigInt(0) in uidValidity checks.
Prevents unhandled promise rejections when close() encounters race conditions.
Prevents an unhandled NoConnection rejection during IDLE recovery.
The fetch() generator releases backpressure when iteration ends early through break or throw.
Null guards in compress() prevent a crash during TLS teardown.
Transform streams now implement _destroy() methods for proper cleanup.
Restores the isClosed check and error logging in initialPREAUTH.
Prevents memory leaks in socket and event handling.
Adds the missing text search property to the TypeScript definitions so developers can use it with type support.
Improves resource cleanup when a connection closes.
Adds logging for download errors that were silently swallowed, making them visible to developers.
Pending mailbox locks are rejected when the connection closes.
Promise rejections are deferred when a connection closes to prevent unhandled rejections.