From 419c57a427a8666c50340e7528d2387e46b997af Mon Sep 17 00:00:00 2001 From: Pierre-Olivier Mercier Date: Sun, 29 Mar 2026 19:25:32 +0700 Subject: [PATCH] Add README with usage, keybindings, and project context Co-Authored-By: Claude Sonnet 4.6 --- README.md | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..c192799 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# mqv — Mail Queue Viewer + +A quick-and-dirty TUI for browsing the Postfix deferred queue, built mutt-style. + +I wanted this tool for a long time. Claude finally made it happen. + + +## What it does + +`mqv` gives you a keyboard-driven terminal interface to inspect your Postfix mail queue — read messages, browse attachments, save EML files — without leaving the terminal. + +``` + ABC1234 Mar 29 10:00 sender@example.com Subject line here + DEF5678 Mar 28 14:32 other@example.com Another message + ... +``` + + +## Requirements + +- Go 1.21+ +- `postqueue` and `postcat` in `$PATH` (i.e. Postfix installed) +- Run as a user with read access to the Postfix queue +- Optional: `w3m` for rendering HTML parts as plain text + + +## Install + +```bash +git clone https://github.com/nemunaire/mqv +cd mqv +go build -o mqv . +./mqv +``` + +Or install directly: + +```bash +go install github.com/nemunaire/mqv@latest +``` + +## Screens & keybindings + +### Queue list + +| Key | Action | +|------------|-------------------------------------| +| `↑` / `↓` | Navigate messages | +| `Enter` | Open message | +| `r` | Refresh queue | +| `q` | Quit | + +Subjects are fetched lazily in parallel via `postcat` as the list loads; a progress bar tracks completion. + +### Message view + +| Key | Action | +|-----------------|---------------------------------| +| `↑↓` / `Space` / `PgUp` / `PgDn` | Scroll | +| `H` | Toggle full headers / short headers | +| `s` | Save raw EML to `~/QUEUEID.eml` | +| `v` | Browse MIME parts | +| `q` | Back to queue list | + +Headers are RFC 2047 decoded. The body is decoded from quoted-printable or base64. HTML parts are rendered via `w3m` if available, otherwise shown as-is. + +### MIME parts browser + +| Key | Action | +|------------|-------------------------------------| +| `↑↓` / `j/k` | Navigate parts | +| `Enter` | View text part inline | +| `s` | Save part to file (prompts for name) | +| `q` / `Esc`| Back to message view | + +### Part view + +| Key | Action | +|-----------------|---------------------| +| `↑↓` / `Space` / `PgUp` / `PgDn` | Scroll | +| `q` / `Esc` | Back to parts list | + + +## How it works + +1. Runs `postqueue -p` and parses the output to build the queue list. +2. For each entry, fetches the subject via `postcat -qh MSGID` in parallel. +3. On `Enter`, loads the full message with `postcat -qbh MSGID` and renders it in a scrollable viewport. +4. MIME parsing is done in pure Go (`mime/multipart`, `mime/quotedprintable`) — no external dependencies for message decoding. +5. Charset decoding handles ISO-8859-1, Windows-1252, and anything in the IANA index via `golang.org/x/text`. + + +## Stack + +- [bubbletea](https://github.com/charmbracelet/bubbletea) — Elm-architecture TUI framework +- [bubbles](https://github.com/charmbracelet/bubbles) — list, viewport, progress, textinput components +- [lipgloss](https://github.com/charmbracelet/lipgloss) — terminal styling +- [x/text](https://pkg.go.dev/golang.org/x/text) — charset decoding + + +## License + +MIT