{"_id":"@compeso/node-red-contrib-imap-email","_rev":"3-b6311061b1d09ab96568a55ac0c8ccb8","name":"@compeso/node-red-contrib-imap-email","dist-tags":{"latest":"1.1.0"},"versions":{"1.0.0":{"name":"@compeso/node-red-contrib-imap-email","version":"1.0.0","keywords":["node-red","imap","email","mail","imap-email","at-least-once","ack"],"author":{"name":"compeso"},"license":"MIT","_id":"@compeso/node-red-contrib-imap-email@1.0.0","maintainers":[{"name":"harpau","email":"hpaulus@compeso.com"}],"homepage":"https://github.com/Harpau/node-red-contrib-imap-email#readme","bugs":{"url":"https://github.com/Harpau/node-red-contrib-imap-email/issues"},"dist":{"shasum":"bc04d7d0060041a73f6acf2dece5913460d07a17","tarball":"https://registry.npmjs.org/@compeso/node-red-contrib-imap-email/-/node-red-contrib-imap-email-1.0.0.tgz","fileCount":21,"integrity":"sha512-q3wNnnkGNoRmUR4cmnWrjqe05TnY5aKl2Aa7fyzqnjsfWJICbADmjBV+q+VLGQ5f7f4JnHdX1WGBhY+6w1c5Ig==","signatures":[{"sig":"MEQCIGMy6e7iI7k9tHCR9j4cWCdn/3hOlijDsuUnNGwo5RKMAiBQoS0slmcgEU5EDhh9DA3ZNg99cFNrbJGAcA3e3cmEVw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":190051},"engines":{"node":">=22.0.0"},"gitHead":"c9c4917626c3ee183c4c5c3be45d280d0276b935","scripts":{"test":"node --test test/*.test.js","pack:check":"npm pack --dry-run","pack:local":"npm pack"},"_npmUser":{"name":"harpau","email":"hpaulus@compeso.com"},"node-red":{"nodes":{"imap-email in":"nodes/imap-email-in.js","imap-email ack":"nodes/imap-email-ack.js","imap-email account":"nodes/imap-email-account.js"},"version":">=4.0.0"},"repository":{"url":"git+https://github.com/Harpau/node-red-contrib-imap-email.git","type":"git"},"_npmVersion":"10.9.2","description":"Node-RED IMAP email nodes with externally triggered bounded cursor-window fetch, at-least-once ACK actions, diagnostics, timings, and comprehensive help documentation.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"imapflow":"1.0.76","mailparser":"3.9.10"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/node-red-contrib-imap-email_1.0.0_1781695385627_0.29031311204816124","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@compeso/node-red-contrib-imap-email","version":"1.0.1","keywords":["node-red","imap","email","mail","imap-email","at-least-once","ack"],"author":{"name":"compeso"},"license":"MIT","_id":"@compeso/node-red-contrib-imap-email@1.0.1","maintainers":[{"name":"harpau","email":"hpaulus@compeso.com"}],"homepage":"https://github.com/Harpau/node-red-contrib-imap-email#readme","bugs":{"url":"https://github.com/Harpau/node-red-contrib-imap-email/issues"},"dist":{"shasum":"11389dcfd6743e5fa3ce4125546754a8a51c6918","tarball":"https://registry.npmjs.org/@compeso/node-red-contrib-imap-email/-/node-red-contrib-imap-email-1.0.1.tgz","fileCount":21,"integrity":"sha512-O9HCFsqrwapZbADatGBgWScZPhojRF1CL+rzOYDjwxvkvgvAXYKc5nSbSHjpDorc9jxZojAGHBcr0jXytETuYg==","signatures":[{"sig":"MEUCICJY/iA3DcI/6eIzOCVqcZyETHQ4u6xUdRfl7UiQ4NBHAiEAiQSbZGTba2C59Q8c8wjgOsbOhjqW4St0A/9riSBji14=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":196810},"engines":{"node":">=22.0.0"},"gitHead":"1da7fc3f23ff895f59af977ff9710fad3a55bf4b","scripts":{"test":"node --test test/*.test.js","pack:check":"npm pack --dry-run","pack:local":"npm pack"},"_npmUser":{"name":"harpau","email":"hpaulus@compeso.com"},"node-red":{"nodes":{"imap-email in":"nodes/imap-email-in.js","imap-email ack":"nodes/imap-email-ack.js","imap-email account":"nodes/imap-email-account.js"},"version":">=4.0.0"},"repository":{"url":"git+https://github.com/Harpau/node-red-contrib-imap-email.git","type":"git"},"_npmVersion":"10.9.2","description":"Node-RED IMAP email nodes with externally triggered bounded cursor-window fetch, at-least-once ACK actions, diagnostics, timings, and comprehensive help documentation.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"imapflow":"^1.4.2","mailparser":"^3.9.11"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/node-red-contrib-imap-email_1.0.1_1782047436227_0.9120789154565931","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"_id":"@compeso/node-red-contrib-imap-email@1.1.0","bugs":{"url":"https://github.com/Harpau/node-red-contrib-imap-email/issues"},"dist":{"shasum":"a7945ada51d3262f6de8c24a9ae37c570173329e","tarball":"https://registry.npmjs.org/@compeso/node-red-contrib-imap-email/-/node-red-contrib-imap-email-1.1.0.tgz","fileCount":24,"integrity":"sha512-ZhHtGG61McmmD8Ma8D1YkfwvpDhBNGqqK88IZjmjGqmQm+cl2IP/EsHBwgHAaGpbE5i6WBK+SPmuDSR5z9BxIg==","signatures":[{"sig":"MEQCIBp1qtic0QLnVrU+HGgpa7dfeIHWbG5w8IoCsYJjNthBAiBgnJMWm5ovb974T+Ib9HCnkuiS45riUQxmaSOQS/z8wQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIA6oDoKrQigojuwG7tGzUNOEgXt0f38fm4zrrOD3fCVIAiBiCALjmO5hzPub9Dwu2Bmof3na5e8AFbTU07NfL9xxBg=="}],"unpackedSize":248697},"name":"@compeso/node-red-contrib-imap-email","_from":"file:compeso-node-red-contrib-imap-email-1.1.0.tgz","author":{"name":"compeso"},"engines":{"node":">=22.0.0"},"license":"MIT","scripts":{"test":"node --test test/*.test.js","pack:check":"npm pack --dry-run","pack:local":"npm pack","test:integration":"node --test test/integration/*.test.js"},"version":"1.1.0","_npmUser":{"name":"harpau","email":"hpaulus@compeso.com"},"homepage":"https://github.com/Harpau/node-red-contrib-imap-email#readme","keywords":["node-red","imap","email","mail","imap-email","at-least-once","ack"],"node-red":{"nodes":{"imap-email in":"nodes/imap-email-in.js","imap-email ack":"nodes/imap-email-ack.js","imap-email account":"nodes/imap-email-account.js"},"version":">=4.0.0"},"_resolved":"/Users/hpaulus/src/node-red-contrib-imap-email/compeso-node-red-contrib-imap-email-1.1.0.tgz","_integrity":"sha512-ZhHtGG61McmmD8Ma8D1YkfwvpDhBNGqqK88IZjmjGqmQm+cl2IP/EsHBwgHAaGpbE5i6WBK+SPmuDSR5z9BxIg==","repository":{"url":"git+https://github.com/Harpau/node-red-contrib-imap-email.git","type":"git"},"_npmVersion":"10.9.2","description":"Node-RED IMAP email nodes with externally triggered bounded cursor-window fetch, at-least-once ACK actions, diagnostics, timings, and comprehensive help documentation.","directories":{},"maintainers":[{"name":"harpau","email":"hpaulus@compeso.com"}],"_nodeVersion":"22.14.0","dependencies":{"imapflow":"^2.0.5","mailparser":"^3.9.28"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/node-red-contrib-imap-email_1.1.0_1789567125550_0.2937342992899572"}}},"time":{"created":"2026-06-17T11:23:05.368Z","modified":"2026-09-16T13:58:45.904Z","1.0.0":"2026-06-17T11:23:05.813Z","1.0.1":"2026-06-21T13:10:36.376Z","1.1.0":"2026-09-16T13:58:45.631Z"},"bugs":{"url":"https://github.com/Harpau/node-red-contrib-imap-email/issues"},"author":{"name":"compeso"},"license":"MIT","homepage":"https://github.com/Harpau/node-red-contrib-imap-email#readme","keywords":["node-red","imap","email","mail","imap-email","at-least-once","ack"],"repository":{"url":"git+https://github.com/Harpau/node-red-contrib-imap-email.git","type":"git"},"description":"Node-RED IMAP email nodes with externally triggered bounded cursor-window fetch, at-least-once ACK actions, diagnostics, timings, and comprehensive help documentation.","maintainers":[{"name":"harpau","email":"hpaulus@compeso.com"}],"readme":"# @compeso/node-red-contrib-imap-email\n\nNode-RED nodes for externally triggered IMAP email processing with bounded cursor-window fetch and at-least-once ACK handling.\n\n## Nodes\n\nThe package registers these Node-RED types:\n\n```text\nFlow type           Palette label        Purpose\nimap-email account  imap email account   shared IMAP account configuration\nimap-email in       imap email in        externally triggered bounded cursor-window fetch\nimap-email ack      imap email ack       batched acknowledgement and UID actions\n```\n\n## Requirements\n\n- Node.js `>=22.0.0`\n- Node-RED `>=4.0.0`\n\nNode-RED 5.x can require a stricter Node.js patch level than this package\ndeclares. Check the Node-RED runtime requirement when upgrading Node-RED itself.\n\n## Installation\n\nFrom the npm registry:\n\n```bash\ncd ~/.node-red\nnpm install @compeso/node-red-contrib-imap-email\n```\n\nFrom GitHub during development:\n\n```bash\ncd ~/.node-red\nnpm install github:Harpau/node-red-contrib-imap-email\n```\n\nFrom a local checkout:\n\n```bash\ncd /path/to/node-red-contrib-imap-email\nnpm install\nnpm link\n\ncd ~/.node-red\nnpm link @compeso/node-red-contrib-imap-email\n```\n\nRestart Node-RED after installation.\n\nFor development or release testing, pack the checkout and install the resulting\ntarball in an isolated Node-RED test instance. See\n[local test instructions](docs/INSTALL_DE.md).\n\n## Example Flow\n\nImport [examples/basic-at-least-once-flow.json](examples/basic-at-least-once-flow.json) in Node-RED, open the `imap email account` config node, and enter your IMAP username and password. The example tab is disabled by default, the Inject node does not run automatically, and the ACK path only marks messages as seen. The visible palette labels use spaces; the stored Flow-JSON types use the `imap-email ...` prefix.\n\nMinimal flow:\n\n```text\nInject / scheduler / HTTP trigger\n  -> imap-email in\n      -> your successful processing\n          -> imap-email ack\n```\n\nOnly wire messages to `imap-email ack` after all processing that must succeed has actually succeeded.\n\n`imap-email ack` can be configured multiple times in one flow. Typical modes:\n\n```text\ndelete       delete the mail by UID and complete it; requires IMAP UIDPLUS\nmove         optionally update flags, move the mail and complete it; requires native IMAP MOVE\ncopy         copy the mail to a target folder, then optionally update source flags\nflag         set or clear flags, keep the mail and complete it\nset by msg.imap.ackAction\n             read action, target folder and flags from the message\n```\n\nThe ack node can set or clear `\\Seen`, `\\Answered`, `\\Flagged`, other IMAP\nsystem flags such as `\\Draft`, and custom keywords such as `$Processed` in\n`flag`, `move` and `copy` mode. With `move`, flags are updated on the source\nmessage before it is moved. With `copy`, the message is copied first and the\nconfigured ACK flag changes are then applied only to the source message. They\nare not applied to the target copy, though the IMAP server may copy flags that\nalready existed on the source message. Use `delete` to delete mail; setting\n`\\Deleted` as a raw flag is an advanced flag operation and does not replace the\ndelete action.\n\n## Connection Check on Start\n\nAvailable since version `1.1.0`.\n\nEach active `imap email in` and `imap email ack` node automatically checks its\naccount when it starts, without needing an input message. This includes restart,\nfull Deploy and any partial Deploy that restarts the node, including changes to\nits account, credentials or other settings. Nodes that continue running are not\nchecked again. With **Modified Flows**, unchanged nodes in a restarted flow are\nalso checked. Unused accounts and accounts used only by disabled nodes or flows\ncreate no check connection.\n\nNodes using the same account instance share a check while it is running. The\ncheck uses the account's current connection settings and stored credentials;\na static access token takes precedence over a password. The connection is\nshort-lived and closes after the check. A later node start requests a fresh\ncheck; there is no periodic retry or continuous monitoring.\n\nThe following status appears on the input or ACK node:\n\n| Status | Meaning |\n| --- | --- |\n| Yellow ring: `checking connection` | The startup check is running. |\n| Green dot: `connected` | The last startup check succeeded; this is not a persistent connection. |\n| Red ring: `missing account`, `missing host`, `missing username`, `missing credentials` | Complete the account configuration. |\n| Red ring: `authentication failed` | The server rejected authentication. |\n| Red ring: `host not found`, `connection refused`, `connection lost` | The server could not be reached or the connection was lost. |\n| Red ring: `TLS certificate error`, `TLS connection error` | Certificate verification or the TLS connection failed. |\n| Red ring: `connection timeout`, `connection failed` | A time limit or another connection error ended the check. |\n\nThe whole check has a fixed **30-second limit**, including connection setup,\nauthentication and cleanup. Shorter account timeouts still apply. This limit\ndoes not change the timeouts of normal fetch or ACK connections.\n\nSuccess confirms a server-accepted authenticated session. A server that sends\nIMAP `PREAUTH` has already authenticated that session and does not challenge the\nconfigured password or token again. The check does not read messages, change\nflags or test access to a mailbox or permission to perform an ACK action.\n\nDeploy and normal processing can continue while the check runs. A failed check\ndoes not block later fetch or ACK attempts. Normal processing statuses and ACK\nconfiguration errors take priority over the check result. Closing or redeploying\na node cancels its pending result. The check emits no output or stats messages;\nNode-RED **Status** nodes can observe its status changes. Check failures produce\nat most one warning per shared check using fixed error categories and safe\ntechnical codes. Deliberate cancellation does not produce a warning.\n\n## Large Mailboxes\n\n`imap-email in` is designed for mailboxes that may contain many messages. It\ndoes not run an unbounded mailbox-wide search. Instead, each trigger reads one\nor more bounded windows and emits at most the configured batch size. Each\nwindow is streamed and discarded before another window is read; only selected\ncandidate UIDs up to the remaining batch/inflight capacity are kept in memory.\n\nImportant settings:\n\n```text\nBatch size       maximum messages emitted per trigger\nFront window     maximum messages inspected per bounded window\nMax inflight     maximum emitted but not-yet-ACKed messages tracked in memory\nRetry after ms   time after which an un-ACKed message may be emitted again\nScan time ms     initial cursor-window soft time budget; 0 means exactly one cursor window\nUIDs/command     maximum UID count per IMAP command chunk\nMax bytes        maximum RFC822 bytes per message, 0 means unlimited\nChunk bytes      streamed IMAP download chunk size\n```\n\nSelection settings:\n\n```text\nDeleted   Any | Only with flag | Only without flag\nSeen      Any | Only with flag | Only without flag\nAnswered  Any | Only with flag | Only without flag\nFlagged   Any | Only with flag | Only without flag\n```\n\nThe defaults are `Deleted = Only without flag` and all other flags set to\n`Any`. These filters are applied only inside bounded windows. A\nselective filter may emit fewer messages than `Batch size`; it never causes a\nfull-mailbox scan to fill the batch. When the cursor reaches the end of the\nmailbox, it wraps back to the first sequence number. The cursor is volatile and\nresets when Node-RED restarts or when IMAP UIDVALIDITY changes.\n\nThe node always uses an adaptive scan strategy. After restart or UIDVALIDITY\nreset it starts in the `cursor-window` phase with full `Front window` sized\nsequence windows. Empty windows are discarded and the node updates its status\nafter every read window. The phase stops when the batch/capacity is filled, the\nmailbox end is reached, or `Scan time ms` expires; `0` means only one cursor\nwindow. If a window contains more selectable messages than the remaining\nbatch/capacity can hold, the scan cursor is kept on that window so a later\ntrigger can continue draining it instead of leaving messages behind. This is\nespecially useful when the ACK node deletes or moves processed mails: after\nthose mails leave the mailbox, remaining messages shift into the held sequence\nwindow and can be drained without being skipped. An empty mailbox with a valid\n`UIDNEXT` is treated as already at the mailbox end.\n\nOnce the mailbox end has been reached without candidate overflow, the node\nrecords the current `UIDNEXT`. Later triggers enter the `new-uid-priority`\nphase: they first read newly arrived UIDs up to a per-trigger `UIDNEXT`\nsnapshot, then read one cyclic backlog window if capacity remains. In this\nphase the new-UID and backlog windows each use about half of `Front window`,\nwith the larger half assigned to new UIDs. The logical new-UID window is still\nbounded by `Front window`, and its UID fetches are additionally split into\ncommands of at most `UIDs/command` UIDs. New UIDs are emitted before backlog\nmessages and in ascending UID order, but the node does not guarantee globally\noldest unread delivery across the whole mailbox. Backlog windows are also held\non candidate overflow. If the new-UID window already covers all messages that\ncurrently exist in the mailbox, the redundant backlog window is skipped.\nNew-UID windows advance to the first UID that did not fit into the current\nbatch, or to the next UID after the last actually read command chunk.\n\nStats report `phase` as the current operating phase (`cursor-window` or\n`new-uid-priority`). `windowPhasesRead` contains the ordered unique window\ntypes read during the trigger (`cursor`, `new-uid`, `backlog`); the last entry\nis the last window type read.\n\nOutput messages include the server flags as an array:\n\n```js\nmsg.imap.flags // for example [\"\\\\Seen\", \"\\\\Flagged\"]\nmsg.imap.flagState // { deleted: false, seen: true, answered: false, flagged: true }\n```\n\nParsed mail headers are emitted in `msg.email.header` as a JSON-serializable\nobject without an `Object` prototype. Use `Object.hasOwn(msg.email.header, key)`\ninstead of `msg.email.header.hasOwnProperty(key)` when checking header presence.\nHeaders with prototype-sensitive names such as `__proto__`, `constructor` or\n`prototype` are preserved under neutralized names.\n\nMessage bodies are downloaded as streams after the bounded front window has\nselected candidate UIDs. Attachments are drained without buffering unless\n`Attachments` is enabled. `Raw source` intentionally buffers the full RFC822\nmessage in `msg.raw`; keep it disabled for very large messages. Set `Max bytes`\nto a positive value to reject oversized messages on output 2 with\n`msg.imap.ackToken` instead of parsing them.\n\n## Delivery Semantics\n\nThe package provides at-least-once delivery.\n\n```text\nACK action succeeded = successfully processed and ACKed\nACK action failed    = not successfully ACKed\nDuplicate delivery   = possible\nExactly once         = not guaranteed\n```\n\nThe inflight registry is volatile process memory. If Node-RED restarts after a message was emitted but before it was ACKed, the message remains in the mailbox and may be emitted again.\n\nCompletion guards for successfully ACKed inflight generations are also kept\nonly in process memory and are bounded by a per-queue TTL and hard cap. After\nthat bounded best-effort window, an extremely old fetch generation may be\neligible for re-marking again. This keeps memory use bounded and preserves the\npackage's at-least-once model; it is not an exactly-once guarantee.\n\nA reported IMAP action failure is not acknowledged as success. In that case\noutput 2 receives the original message with\n`msg.imapAck.ok = false`, and the inflight entry remains available for a later\nretry.\n\nTo avoid unsafe IMAP fallback behavior, `delete` requires server support for\n`UIDPLUS` and `move` requires native `MOVE`. Without those capabilities the ACK\naction fails closed on output 2. `copy` keeps the source message, copies it to\nthe target mailbox first, and then applies any configured flag changes to the\nsource message only.\n\nSince version **1.1.0**, ACK `delete` and input `Expunge window`\nexplicitly confirm setting `\\Deleted`, require a successful delete result and\nthen search only the UIDs in the same bounded chunk to confirm that none remain.\nOnly a successful search with an empty UID result confirms removal.\nThe connection, selected mailbox path and UIDVALIDITY must stay valid throughout.\nThis guards against a historical ImapFlow false-success case; see the\n[DELETE history and fix](docs/KNOWN_ISSUES.md). It adds no mailbox-wide scan.\nThe safeguard adds two commands per deletion chunk: a checked STORE and a\nUID-constrained SEARCH without message content. Existing `UIDs/command` limits\nstill apply; the query uses neither `ALL` nor a wildcard UID range.\n\nA rejected initial flag update stops before EXPUNGE. Once that update succeeds,\nany later failure is partial: flags or deletions may already have taken effect,\nand no rollback is attempted. ACK retains inflight for the affected messages and\nstops later chunks in that group. Input cleanup aborts the current fetch cycle\non a partial result or connection failure; it does not count unconfirmed UIDs\nas expunged or remove them from the registry. Earlier confirmed chunks remain\napplied. A later input trigger can attempt cleanup again.\n\nACK tokens are opaque signed bearer capabilities scoped to the configured IMAP\naccount and to the current in-memory inflight generation. Pass\n`msg.imap.ackToken` from `imap-email in` to `imap-email ack` unchanged. Do not\nbuild, edit, log or expose tokens externally. If a token is missing required\nfields, is unsigned, has been modified, has already completed, or no longer\nmatches the current inflight generation, the ACK node rejects it on output 2\nwithout creating an IMAP client. The internal `queueKey` value is not a stable\npublic API.\n\nFor dynamic decisions, configure `imap-email ack` to\n`set by msg.imap.ackAction` and set `msg.imap.ackAction`:\n\n```js\nmsg.imap.ackAction = {\n  action: \"move\",               // delete, move, copy, flag\n  targetMailbox: \"Archive/Processed\",\n  flags: {\n    seen: \"set\",                // ignore, set, clear\n    answered: \"ignore\",\n    flagged: \"clear\",\n    add: [\"$Processed\"],\n    remove: [\"\\\\Draft\"]\n  }\n};\n```\n\nSuccessful completions add `msg.imapAck` with fields such as `action`,\n`disposition`, `mailbox`, `targetMailbox`, `uid`, `uidValidity`, `flags`,\n`range` and `completed`. Failed completions may include\n`msg.imapAck.partial = true` when a state-changing IMAP step already succeeded\nbefore a later step failed. For `delete`, this includes failure after confirmed\nsetting of `\\Deleted`, even when final removal could not be confirmed. Retaining\ninflight cannot restore removed messages; remaining `\\Deleted` messages are\nexcluded by the default input filter. For `copy`, a successful copy followed by a failed\nsource flag update is partial; because Inflight is kept for retry, a retry may\ncreate another copy in the target mailbox.\n\n## Current Limits\n\n- OAuth2 token acquisition and refresh are not implemented. The account node supports username/password and an optional static access token field.\n\n## Development Checks\n\n```bash\nnpm install\nnpm audit --omit=dev\nnpm test\nnpm run pack:check\ngit diff --check\n```\n\nSee [the release checklist](docs/RELEASE_DE.md) for strict minimum-version\ninstalls, actual-library tests and the required isolated Node-RED deploy tests.\nExternal provider tests and current GitHub CI results are additional release\nrequirements; historical results do not establish readiness for a new version.\n\nDo not publish this package to npm or flows.nodered.org without explicit human approval.\n","readmeFilename":"README.md"}