Skip to content

feat(cli): add mail manage commands - #1755

Open
Robin-Everaars wants to merge 5 commits into
floatpane:release/v1from
Robin-Everaars:feature/cli-manage
Open

Robin-Everaars wants to merge 5 commits into
floatpane:release/v1from
Robin-Everaars:feature/cli-manage

Conversation

@Robin-Everaars

@Robin-Everaars Robin-Everaars commented Oct 27, 2026 •

Copy link
Copy Markdown

What?

Adds the commands that change mail:

matcha archive     [--from <email>] <folder> <uids>
matcha delete      [--from <email>] <folder> <uids>
matcha mark-read   [--from <email>] <folder> <uids>
matcha mark-unread [--from <email>] <folder> <uids>
matcha move        [--from <email>] <src> <dst> <uids>

UIDs are comma- or space-separated. The five share one implementation, so they come in one PR.

Also a fix: the daemon's MarkRead handler logged failures per UID but still reported success over RPC, so mark-read through a running daemon said it worked when it didn't. It now returns the joined errors, like the other mutating handlers and direct mode.

Why?

Closes #1642 together with the earlier PRs. Depends on #1754.

This is one of five small PRs that replace #1680, as asked there: rebuilt on release/v1 and split per command. They stack, so please merge them in order. Each one shows its predecessors' commits until those are merged.

  1. feat(cli): add folders subcommand #1751 folders
  2. feat(cli): add list subcommand #1752 list
  3. feat(cli): add read subcommand #1753 read
  4. feat(cli): add search subcommand #1754 search
  5. feat(cli): add mail manage commands #1755 archive, delete, mark-read, mark-unread, move

Every step passes gofmt, go vet, go test ./..., go mod tidy and golangci-lint on the new code.

Add `matcha folders [--from <email>] [--json]`, the first read-only
mail command next to `send`.

The shared plumbing for the follow-up commands lives in cli/util.go
(account resolution by --from, matching Email and then FetchEmail
case-insensitively) and cli/main.go (hookable config loader, service
constructor and output writers for tests).

daemonclient gains NewCLIClient(cfg, autoStart). With autoStart off, a
one-shot command uses a running daemon and otherwise connects directly
instead of forking a daemon. NewService keeps its behaviour.

Refs floatpane#1642
Add `matcha list [folder] [--from <email>] [--json]`, which prints the
newest 50 messages of a folder (INBOX by default) as a table or as JSON
with uid, from, subject, date and is_read.

Adds the helpers the later read, search and manage commands share:
INBOX normalization, flag parsing that allows flags after positionals,
and the table/JSON email renderer.

Refs floatpane#1642
Add `matcha read [--from <email>] [--json] <folder> <uid>`. A single
numeric argument reads that UID from INBOX. Plain output prints the
body; --json returns body, mime_type and attachment metadata.

backend.Attachment gets explicit snake_case JSON names, and its raw
Data bytes are excluded so scripts never receive the payload as base64.

Refs floatpane#1642
Add `matcha search [--from <email>] [--json] <folder> <query>`, using
the same query syntax as the TUI (from:, to:, subject:, body:, since:,
before:, larger:). Unquoted terms after the folder are joined, so
`matcha search INBOX from:a subject:b` keeps both terms.

Search was not reachable through the service layer yet, so this adds
Search to daemonclient.Service (daemon and direct), a Search RPC method
and its daemon handler. The daemon gets the raw query and parses it
itself.

Refs floatpane#1642
Add the mail-managing subcommands:

  matcha archive     [--from <email>] <folder> <uids>
  matcha delete      [--from <email>] <folder> <uids>
  matcha mark-read   [--from <email>] <folder> <uids>
  matcha mark-unread [--from <email>] <folder> <uids>
  matcha move        [--from <email>] <src> <dst> <uids>

UIDs are comma- or space-separated. They share one implementation,
so they come as one change.

The daemon's MarkRead handler logged per-UID failures but still
reported success over RPC, so `mark-read` through a running daemon
said it worked when it did not. It now returns the joined errors, like
the other mutating handlers and direct mode.

Refs floatpane#1642
@floatpanebot

Copy link
Copy Markdown
Member

This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR might be rejected due to its size.

@floatpanebot floatpanebot added bug Something isn't working enhancement New feature or request labels Oct 27, 2026

@floatpanebot floatpanebot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Robin-Everaars! Please fix the following issues with your PR:

  • Title: Is too long (42 characters). The PR title must be strictly under 40 characters.

@floatpanebot floatpanebot added area/cli CLI flags / commands area/daemon Daemon / RPC labels Oct 27, 2026

@floatpanebot floatpanebot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Robin-Everaars! Please fix the following issues with your PR:

  • Title: Is too long (42 characters). The PR title must be strictly under 40 characters.

@Robin-Everaars Robin-Everaars changed the title feat(cli): add archive, delete, mark, move feat(cli): add mail manage commands Oct 27, 2026
@floatpanebot
floatpanebot dismissed stale reviews from themself October 27, 2026 23:00

Formatting issues have been resolved. Thank you!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cli CLI flags / commands area/daemon Daemon / RPC bug Something isn't working enhancement New feature or request size/XL Diff: 800+ lines target/v1 PR targets the release/v1 branch directly

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants