title: Reading Emails weight: 4#
Emails are rendered as styled Markdown in the terminal using glamour. The reader supports vim-style navigation.
Navigation#
| Key | Action |
|---|---|
j / k |
scroll line by line |
space / d |
page down / up |
gg |
jump to top of email |
G |
jump to bottom of email |
h / q / esc |
back to inbox |
Opening Emails Externally#
| Key | Action |
|---|---|
e |
open in $EDITOR (read-only) — search, copy, vim motions |
o |
open in w3m (terminal browser, clickable links) |
O |
open in $BROWSER (GUI browser, images rendered) |
ctrl+o |
open 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 1–9 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):
- 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").
- Generic 1×1 pixel heuristic — catches custom/branded tracking domains not on the list by detecting
<img>tags with emptyaltAND 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:
![]()
And within an email open:
![]()
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 (1–9, 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,
spaceworks as page-down as usual
Attachments#
Attachments are listed in the reader header:
Attach: [1] report.pdf [2] photo.png
Press 1–9 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:
- Message-ID / In-Reply-To headers — proper RFC 2822 threading chain
- 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\Answeredflag, 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:

Replying, Forwarding, and Drafts#
| Key | Action |
|---|---|
r |
reply to sender |
ctrl+r |
reply-all (sender + all CC recipients) |
f |
forward email |
T |
show full conversation thread across folders |
E |
continue 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
enterorl), 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
\Seenon the server - If you exit early (press
h,q,esc, orT), 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
nstill 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.