planer
Strips reply quotations and forwarded-message noise from plain-text and HTML emails using regex and DOM-based heuristics.
Repository Health
Technical Analysis
planer is a small, dependency-free Node.js library that extracts the actual new content of an email reply, cutting away quoted history, “On … wrote:” splitters, forwarded-message headers, and client-specific quote markup (Gmail’s gmail_quote, Outlook’s divider divs, Office 365’s #divRplyFwdMsg). It works on both plain-text and HTML message bodies, accepting a caller-supplied Document implementation (browser window.document or jsdom on the server) to do the HTML parsing.
Under the hood it is a JavaScript port of Mailgun’s Python talon library’s quotation-stripping logic (signature stripping was intentionally left out, with a pointer to a separate node-talon port for that). The plain-text algorithm classifies each line of the message with a marker (empty, quote-marked, forwarded, splitter, or actual text) and then trims everything after the detected split point. The HTML algorithm reuses that exact same classifier by injecting numbered checkpoints into the DOM, flattening to plain text, running the classifier, and mapping deleted lines back onto the original DOM nodes for precise removal.
What You Get
extractFrom(msgBody, contentType, dom)— single entry point that dispatches to the plain-text or HTML extractor based oncontentTypeextractFromPlain(msgBody)— line-marker classifier plus splitter regexes tuned for English, French, Dutch, German, Polish, Danish, and Swedish “wrote:” phrasingsextractFromHtml(msgBody, dom)— DOM-aware extraction that cuts Gmail quote blocks, Outlook/Office 365 splitter divs, blockquotes, andFrom:/Date:header blocks before falling back to the plain-text algorithm- Zero runtime dependencies — only requires a
Documentimplementation to be injected for HTML parsing - Precompiled CommonJS output in
lib/so consumers never need the CoffeeScript toolchain
Common Use Cases
- Cleaning inbound email replies before storing or displaying them in a helpdesk, CRM, or ATS inbox
- Stripping quoted history from parsed emails before running them through further NLP or classification
- Normalizing HTML email bodies pulled from IMAP/webhook payloads (e.g. via jsdom on the server) before rendering just the new message
- De-duplicating conversation threads by comparing only the actual new content of each reply
Under The Hood
Architecture
The library splits into three CoffeeScript modules compiled to lib/: planer.coffee (the public entry point — extractFrom, extractFromPlain, extractFromHtml, plus the markMessageLines/processMarkedLines classifier), htmlPlaner.coffee (DOM-specific helpers — cutGmailQuote, cutMicrosoftQuote, cutBlockQuote, cutById, cutFromBlock, and checkpoint injection/removal), and regexes.coffee (a table of locale-aware splitter patterns such as ON_DATE_SMB_WROTE and FROM_COLON_OR_DATE_COLON). The load-bearing abstraction is the checkpoint-then-map-back technique in the HTML path: every text node gets a numbered marker, the DOM is flattened to plain text, the same line classifier used for plain-text emails runs against that flattened text, and the resulting “lines to delete” are mapped back onto the original DOM nodes via their checkpoint numbers for surgical removal. There is no dependency-injection framework — the Document implementation is passed directly by the caller, keeping the library environment-agnostic between browser and jsdom.
Tech Stack
Source is authored in CoffeeScript and precompiled to CommonJS via coffee -o lib -c src (devDependency coffee-script ^1.10.0); the published main entry (lib/planer.js) is plain JS so consumers never touch CoffeeScript directly. There are no runtime dependencies at all — DOM parsing is entirely delegated to a caller-supplied Document, with jsdom ^11.6.0 present only as a devDependency for the test suite. Tests run on mocha ^2.3.4 with chai ^3.4.1 assertions. No bundler, no TypeScript, no web/ORM framework — it is a narrowly scoped, dependency-free utility package usable from both Node and the browser.
Code Quality
Two test files (planerText.test.coffee, planerHtml.test.coffee) exercise dozens of plain-text and HTML edge cases, including multi-language “wrote:” phrasing and fixture HTML files for Outlook, Office 365, and Microsoft namespace quirks under test/examples/html/. Error handling is explicit but minimal — unknown content types or a missing dom argument are logged via console.warn/console.error rather than thrown, and there is no TypeScript or runtime schema validation. Naming is consistent CoffeeScript convention, and the core algorithm functions carry docblock-style comments explaining marker semantics. CI runs CodeQL security scanning and a dependency-enforcement workflow; no dedicated lint/format config was found in the repo.
What Makes It Unique
The checkpoint-injection technique for HTML quote-stripping is the library’s real differentiator: rather than relying only on markup heuristics (a gmail_quote class, blockquote tags, vendor-specific splitter divs), it falls back to running the exact same locale-aware plain-text classifier against a checkpointed, flattened text view of the DOM, then maps the result back onto DOM nodes for precise removal. This lets a single classifier work correctly across both plain-text and rich HTML emails. It is a derivative, JS-native port of the ideas in Mailgun’s Python talon library, adapted to browser/jsdom DOM APIs instead of Python’s html5lib/lxml — a solid, non-trivial solution to a persistently annoying problem rather than a wholly novel algorithm.