Skip to content
Reading Emails

Reading Emails

Emails are rendered as styled Markdown in the terminal using glamour. The reader supports vim-style navigation.

Navigation

KeyAction
j / kscroll line by line
space / dpage down / up
ggjump to top of email
Gjump to bottom of email
h / q / escback to inbox

Opening Emails Externally

KeyAction
eopen in $EDITOR (read-only) — search, copy, vim motions
oopen in w3m (terminal browser, clickable links)
Oopen in $BROWSER (GUI browser, images rendered)
ctrl+oopen newsletter web version in $BROWSER (from List-Post header)

Images

Remote images appear as [Image: alt] placeholders, keeping the reading experience clean and fast. To see images, press O to open in your browser.

Inline / attached images (e.g. screenshots pasted into an email) are listed in the reader header: Attach: [1] screenshot.png [2] report.pdf. Press 19 to download to ~/Downloads/ and open with xdg-open. Inline images also show [Image: filename.png] placeholders at their position in the body text.

When you press O to open in the browser, inline images are extracted from the email and saved to temp files. The HTML cid: references are rewritten to file:// paths so the browser renders them — including images sent by other people (not just your own).

Spy Pixel Blocking

neomd automatically detects and blocks tracking pixels, similar to HEY’s spy pixel blocker. Since the TUI renders emails as styled Markdown via glamour, remote images are never fetched — senders cannot tell if you read their email.

Two-layer detection (same approach as HEY):

  1. Curated denylist — 150+ tracking services with URL pattern matching, sourced from Simplify (BSD-3-Clause), LeaveMeAlone (CC-BY 3.0), and DHH’s original HEY list (MIT). Covers Mailchimp, HubSpot, SendGrid, ConvertKit, Substack, Amazon, Facebook, LinkedIn, and many more. When matched, the service name is shown (e.g. “Mailchimp”).
  2. Generic 1×1 pixel heuristic — catches custom/branded tracking domains not on the list by detecting <img> tags with empty alt AND tiny dimensions (both width/height 0–1) or CSS hiding (display:none). Layout spacers (e.g. 1×50) are not flagged.

When tracking pixels are detected, neomd shows:

  • ° indicator in the inbox list (orange, next to the attachment @ column)
  • ° N spy pixel(s) blocked (ServiceName) in the reader header with tracker attribution

Scanning: Spy pixels are detected when you read an email. To scan all emails in the current folder at once, press <space>S or run :scan-spy-pixels (alias :ssp). The scan runs in the background, skips already-scanned emails, and uses IMAP PEEK (won’t mark emails as read). Results are cached in ~/.cache/neomd/spy_pixels and persist across restarts.

When you press O to open in the browser, remote images load normally — you’re explicitly choosing to see the full email. Tracking pixel blocking is a TUI-level protection.

This is how it looks:

In overview: spy

And within an email open:

spy

Links

Links in emails are automatically numbered inline where they appear in the body. A link like Check out our blog renders as Check out our blog [1] in the terminal.

Press space then a digit (19, 0 for 10th) to open the link in $BROWSER.

  • Up to 10 links per email, deduplicated by URL
  • Numbers appear inline so you can see them while reading without scrolling
  • If an email has no links, space works as page-down as usual

Attachments

Attachments are listed in the reader header:

Attach:  [1] report.pdf  [2] photo.png

Press 19 to download attachment N to ~/Downloads/ and open it with xdg-open. Filenames are deduplicated automatically if a file already exists.

Download Raw Email Source

Press space then d in the reader to download the full raw email source (.eml file) to ~/Downloads/. The file is named neomd-YYYYMMDD-<subject>.eml using the email’s date and sanitized subject line.

This is useful for archiving emails, debugging headers, or importing into other email clients. The status bar shows a green confirmation when the download completes.

Threaded Inbox

Related emails are automatically grouped together in the inbox list. Threads are detected using a hybrid approach:

  1. Message-ID / In-Reply-To headers — proper RFC 2822 threading chain
  2. Subject + participant fallback — emails with the same normalized subject (stripped of Re:, Fwd:, etc.) and overlapping participants (From/To) are grouped together

Threads display with a Twitter-style vertical connector line:

  1  ·17:43  │ rafaelxxxxxxxxxxx@g…  Re: Re: AUR Neomd              (12K)
  2  ·16:30 ·╰  rafaelxxxxxxxxxxx@g…  Re: AUR Neomd                  (10K)
  3 N 19:50  │ Bla blabla   via Li…  Jenna just messaged you        (38K)
  4 N 18:53  │ Bla blabla   via Li…  Jenna just messaged you        (38K)
  5 N 17:59  ╰ Bla blabla   via Li…  Jenna just messaged you        (38K)
  6   18:46    LinkedIn              tom Weller replied to ...      (45K)
  7  ·14:22  · Simon Späti           Data pipeline question          (5K)
  • · reply indicator — you’ve replied to this email (IMAP \Answered flag, works across clients)
  • ·╰ reply indicator within a thread
  • connects thread members (newest on top)
  • marks the root/oldest email at the bottom of each thread
  • ° spy pixel indicator — tracking pixels were detected and blocked (shown after first read)
  • Non-threaded emails show no connector (clean, no visual noise)
  • Threads are sorted by their most recent email, so active conversations float to the top

Or as image: neomd

Replying, Forwarding, and Drafts

KeyAction
rreply to sender
ctrl+rreply-all (sender + all CC recipients)
fforward email
Tshow full conversation thread across folders
Econtinue draft (only in Drafts folder) — re-opens as editable compose

Conversation View

Press T from the inbox list or while reading an email to see the full conversation across folders. neomd searches Inbox, Sent, Archive, Waiting, and other configured folders for related emails — matching by normalized subject and participant overlap.

Results display in a temporary “Thread” tab:

  • Each email shows [Folder] prefix (e.g. [Sent], [Inbox], [Archive])
  • Threading connectors (/) show the conversation structure
  • Press Enter to read any email, Esc to return to previous view

Also available as :thread (alias :t) from the command line.

Mark as Read Behavior

Neomd marks emails as read after you’ve spent time viewing them, not immediately when opened. This prevents accidental marking when quickly peeking at emails.

How it works:

  • When you open an email (press enter or l), neomd fetches the full body from IMAP
  • Once the body loads, a timer starts (default: 7 seconds)
  • If you stay in the reader for the full duration, the email is marked as \Seen on the server
  • If you exit early (press h, q, esc, or T), the email stays unread

Configuration:

[ui]
mark_as_read_after_secs = 7   # wait 7 seconds (default)
# mark_as_read_after_secs = 0   # immediate marking (no timer)
# mark_as_read_after_secs = 10  # 10 seconds

Set to 0 for immediate marking (as soon as the body finishes loading). Set to any value in seconds to customize the delay.

UI behavior:

  • The local inbox list updates immediately when an email is marked as read — no need to manually refresh
  • The unread indicator (N) disappears as soon as marking completes
  • Manual toggle with n still works to mark/unmark emails at any time

Reply Indicator

Emails you’ve replied to show a · dot in the inbox list. This uses the standard IMAP \Answered flag, so it works across clients — if you reply from webmail, neomd shows it too.