How Markdown Here Detects and Excludes Email Signatures from Rendering

Markdown Here identifies email signatures by recursively scanning the DOM for the standard "--" delimiter followed by whitespace, then excludes that content from the rendering range by manipulating selection boundaries before Markdown conversion.

When converting plaintext email content to formatted Markdown, including the sender's signature creates visual clutter and formatting errors. The adam-p/markdown-here repository implements a precise two-step detection system in src/common/markdown-here.js that automatically identifies standard email signature delimiters and removes them from the operational range before rendering occurs.

Locating the Signature Start with findSignatureStart

The detection process begins in the findSignatureStart(startElem) function defined at lines 56-71, which traverses the DOM tree of the focused element to locate signature boundaries while ignoring quoted content.

The Signature Delimiter Pattern

The function searches for text nodes beginning with the standard email signature marker: two hyphens followed by whitespace or a non-breaking space. It validates this pattern using the regular expression ^--[\s\u00a0]+(\n|$), which matches "--" followed by any whitespace character (including \u00a0) and optionally a newline or end-of-string. This catches variations like "-- ", "-- " (with non-breaking space), or "--\n".

Recursive DOM Traversal Logic

As implemented in lines 56-71, the algorithm examines each child node sequentially. When it encounters a text node matching the delimiter pattern, it applies contextual logic: if the delimiter appears at the very start of the parent element, the entire parent is flagged as the signature; otherwise, only the specific text node is returned. The function deliberately skips blockquote elements to avoid false positives in forwarded messages, and continues recursing into other element children until it finds the last valid delimiter in the document flow.

Excluding Signatures from the Operational Range

Once detected, the signature must be surgically removed from the text range that will be converted to Markdown. This exclusion logic resides in the getOperationalRange(focusedElem) function at lines 139-150.

Range Boundary Manipulation

After obtaining the current selection range, the code invokes findSignatureStart. If a signature node is discovered, the implementation first assigns the CSS class markdown-here-signature to enable separate styling. It then checks if the selection start falls inside the signature using range.isPointInRange(sig, 0). When true, the range's end boundary is moved before the signature element via range.setEndBefore(sig), effectively trimming the signature content from the operational range while preserving it in the original document.

CSS Class Assignment

The assignment of markdown-here-signature serves dual purposes: it marks the element for potential styling in the rendered view, and it provides a hook for debugging the detection algorithm. The class is applied before the range manipulation occurs, ensuring the signature remains identifiable in the DOM even after exclusion from the Markdown conversion process.

Complete Implementation Flow

The signature detection integrates seamlessly into the rendering pipeline:

// Rendering workflow with automatic signature exclusion
var focused = findFocusedElem(document);
var range   = getOperationalRange(focused);   // signature removed here
var html    = renderMarkdown(range.toString());
replaceRange(range, html);                    // inserts rendered HTML

In this flow, getOperationalRange internally invokes findSignatureStart and adjusts the selection boundaries to exclude any detected signature before renderMarkdown processes the text. The excluded signature remains in the email body but never reaches the Markdown parser.

Summary

  • Recursive DOM scanning: The findSignatureStart function (lines 56-71) traverses the focused element's tree to locate signature delimiters matching the pattern ^--[\s\u00a0]+(\n|$).
  • Blockquote exclusion: The algorithm intentionally ignores blockquote elements during traversal to prevent accidental truncation of forwarded message content.
  • Range manipulation: The getOperationalRange function (lines 139-150) excludes detected signatures by moving the selection end point before the signature element using range.setEndBefore(sig).
  • CSS tagging: Detected signatures receive the markdown-here-signature class for potential styling while remaining excluded from Markdown conversion.

Frequently Asked Questions

What regex pattern does Markdown Here use to detect email signatures?

Markdown Here uses the regular expression ^--[\s\u00a0]+(\n|$) to identify signature delimiters. This pattern matches two hyphens at the start of a line followed by whitespace (including non-breaking spaces \u00a0) and optionally a newline or end of string, as implemented in lines 56-71 of src/common/markdown-here.js.

Why does the signature detection ignore blockquote elements?

The findSignatureStart function deliberately skips blockquote elements during traversal because quoted text often contains forwarded messages with signature-like delimiters that should not be treated as the sender's actual email signature. This prevents accidental truncation of quoted content while ensuring only the current composer's signature is detected.

How does Markdown Here prevent the signature from appearing in the rendered output?

After detection in getOperationalRange (lines 139-150), the code checks if the selection start is inside the signature using range.isPointInRange(sig, 0). If true, it calls range.setEndBefore(sig) to move the selection boundary before the signature element, effectively excluding it from the text that gets converted to Markdown while preserving the original content in the email body.

Can detected signatures be styled differently even when excluded?

Yes, when a signature is detected, the code assigns the CSS class markdown-here-signature to the signature element before excluding it from the rendering range. This allows for separate styling of signatures in the DOM even though the content is not included in the Markdown conversion process.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →