Repository navigation
Description
Is your feature request related to a problem?
The CLI docs open with "these work without launching the TUI and are ideal for scripts, cron jobs, and AI agent integration," but on the mail side the only thing you can actually do non-interactively today is matcha send. Reading and managing mail still needs the TUI, so there's no way to script "list what's in this folder", "print this message", or "archive/mark these" without driving the interactive UI. That's the gap between what the docs promise and what's exposed.
Describe the solution you'd like
Expose the read and manage operations as subcommands, following the same pattern matcha send already uses. I'm filing this as one request rather than piecemeal because the groundwork is basically all there: the operations already exist as plain package-level functions in fetcher/ that take a *config.Account and run directly (no daemon needed), which is what runSendCLI calls today. For example:
fetcher.FetchFoldersfetcher.FetchFolderEmails/FetchFolderEmailBodyfetcher.MarkEmailAsReadInMailbox/MarkEmailAsUnreadInMailboxfetcher.ArchiveEmailFromMailbox/DeleteEmailFromMailbox/MoveEmailsToFolderfetcher.SearchMailbox
So a first cut is mostly flag parsing plus an output formatter. Rough shape, mirroring matcha send:
matcha folders [--account <email>]
matcha list --folder INBOX [--account <email>] [--limit 50] [--offset 0]
matcha read --folder INBOX --uid <n> [--account <email>]
matcha search --folder INBOX --query "..." [--account <email>]
matcha mark-read | mark-unread --folder INBOX --uid <n> [--account <email>]
matcha archive | delete --folder INBOX --uid <n> [--account <email>]
matcha move --uid <n> --from INBOX --to Archive [--account <email>]
A --json option on the read commands (list, read, folders, search) would make this genuinely usable from scripts and agents, which the docs already name as a goal. Default to a human-readable table, JSON when asked. Account selection could reuse the same --from matching send already has (login + fetch email).
Describe alternatives you've considered
Scripting the TUI with expect-style input (brittle, breaks on any UI change), or talking to the daemon socket directly (daemonrpc is internal and not a stable contract). Neither is a real substitute for first-class subcommands.
Additional context
runSendCLI in main.go is the template to copy (parse flags, LoadConfig, resolve account, call the fetcher/sender function, print), and new commands slot into cli/ next to config.go, contacts_export.go, dict.go, etc., wired through the os.Args dispatch in main(). matcha also has the daemonclient.Service interface (used by the TUI and daemon) wrapping these same operations mode-agnostically, if routing the CLI through that is preferred for daemon-awareness. Either way the underlying operations already exist, so this is mostly surface work.
Before I build anything though I'd like your read on it: is this something you'd want, and is the command/flag shape roughly right? If it looks good to you I'll take it on and open a PR.
Version: matcha 0.43.0.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
Robin-Everaars commentedon Jul 10, 2026
Couldn't resist taking a crack at this on my fork: https://github.com/Robin-Everaars/matcha/tree/feat/non-interactive-cli
It does list/read/search/folders plus archive/delete/mark-read/mark-unread/move, all through the existing service layer (search needed a new RPC method on the daemon). Same query syntax as the TUI search, and tests for everything.
Would be glad to turn this into a PR if this lines up with what you had in mind!
andrinoff commentedon Jul 10, 2026
@Robin-Everaars could you open a PR, so that we could review, please?
Robin-Everaars commentedon Jul 13, 2026
Opened #1680 for this.
A few notes on where the implementation landed vs. the shape I sketched above:
--folder/--uid, the commands take positionals to match howsendalready reads, e.g.:<uids>accepts more than one, so you can archive/mark a batch in one call.--from, not--account, reusing the exact account-matchingsendalready has (login, with a fetch-email fallback).--jsonon the read side (folders,list,read,search); the read command's JSON includes attachment metadata but omits the raw bytes.daemonclient.Servicerather than calling thefetcherfunctions directly. This was the daemon-aware option I mentioned. A one-shot invocation uses a running daemon if there is one and otherwise falls back to a direct connection, so it never forks a daemon just to run a single command. That needed aSearchmethod adding to the service layer (there was a handler gap), which the PR includes.All commands have unit tests, and
go build/go vet/go test ./...are green.Happy to switch to explicit
--folder/--uidflags or tweak any of the naming if you'd prefer a different shape which is easy to change before merge.floatpanebot commentedon Aug 13, 2026
This has had no activity for 30 days. It will be closed in 14 days unless updated. Comment or remove the
stalelabel to keep it open.floatpanebot commentedon Aug 27, 2026
Closing due to inactivity. Reopen if still relevant.
Robin-Everaars commentedon Oct 27, 2026
I've split #1680 into five smaller PRs against
release/v1, as you asked there. Merge them in order:The stale bot closed this issue while I was redoing the work, and I can't reopen it myself. @andrinoff, could you reopen it? #1755 closes it once the stack is in.