Skip to content

feat(mail): env password, list enhancements, and batch command (0.2.6) - #13

Open
bscott wants to merge 4 commits into
masterfrom
v0.2.6
Open

feat(mail): env password, list enhancements, and batch command (0.2.6)#13
bscott wants to merge 4 commits into
masterfrom
v0.2.6

Conversation

@bscott

@bscott bscott commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Implements three feature requests (#8, #9, #10) for automated/headless email workflows. Reimplemented from scratch (issue branches used only as reference); builds clean, go vet clean, all tests pass.

#8 — Bridge password from env var

  • GetPassword() checks PM_CLI_BRIDGE_PASSWORD before the system keyring → enables headless/CI use with no secret service.
  • Interactive use unchanged (env var only consulted when set & non-empty). Env-takes-precedence is documented.

#9mail list enhancements

  • Fixes the --unread undercount: --unread/--flagged now use server-side IMAP SEARCH, so results honor --limit instead of being thinned by client-side filtering. The two can be combined.
  • Adds from_address, to, message_id, in_reply_to to list/search JSON (all already in the ENVELOPE — zero extra fetch). Previously from dropped the address whenever a display name was present.
  • Adds --fields (project onto named JSON fields) and --compact (bare array). JSON-only; text output unchanged.
  • ListMessages now takes a ListOptions struct; all callers updated.

#10mail batch

  • New mail batch subcommand runs a JSON array of ops (label, unlabel, archive, move, flag, delete) over a single IMAP session.
  • All ops validated before connecting; names with IMAP special chars rejected — including the source mailbox (closed a gap vs. the original proposal); 10MB input cap; errors sanitized via safetext.
  • --stop-on-error halts after first failure; per-op results + totals reported.

Tests & docs

  • New tests: env-var precedence, field parsing/projection, batch validation (incl. CRLF/wildcard rejection) and decode.
  • docs/commands.md, new docs/batch-format.md, and the --help-json schema updated. Version bumped to 0.2.6.

⚠️ Sequencing note

mail batch routes through CopyMessages/DeleteMessages/MoveMessages. Its per-op success reporting is only fully accurate once #11 (silent no-op detection in STORE/COPY) lands — and #11's COPY check still needs the UIDPLUS/COPYUID verification flagged in that review. Recommend landing #11 before relying on batch's label/unlabel results.


Supersedes #12 (closed automatically when its branch was renamed to v0.2.6).

bscott added 4 commits June 1, 2026 19:12
Implements three feature requests for automated/headless email workflows.

#8 - Bridge password from environment:
- GetPassword() checks PM_CLI_BRIDGE_PASSWORD before the system keyring,
  enabling headless/CI use where no secret service is available. Interactive
  use is unchanged (env var only consulted when set and non-empty).

#9 - mail list enhancements:
- --unread/--flagged now use server-side IMAP SEARCH, so results honor
  --limit instead of being thinned by client-side filtering.
- Adds from_address, to, message_id, and in_reply_to to list/search output
  (all already in the ENVELOPE, no extra fetch).
- Adds --fields (project onto named JSON fields) and --compact (bare array).
- ListMessages now takes a ListOptions struct; all callers updated.

#10 - mail batch:
- New 'mail batch' subcommand executes a JSON array of operations (label,
  unlabel, archive, move, flag, delete) over a single IMAP session.
- Operations are fully validated before connecting; mailbox/label names with
  IMAP special characters (including the source mailbox) are rejected; input
  is capped at 10MB; errors are sanitized for terminal output.
- --stop-on-error halts after the first failure; per-op results reported.

Docs (commands.md, batch-format.md) and JSON help schema updated; version
bumped to 0.3.0.

Note: batch's per-op success reporting depends on issue #11 (silent no-op
detection in STORE/COPY) for full accuracy.
Report-level credit to @Juan-de-Costa-Rica for the detailed issue reports.
Implementation written fresh against the issues.
No v0.3.0 release/tag exists yet; latest published release is v0.2.5.
These changes ship in the 0.2.6 line, not a 0.3.0 minor release.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@Juan-de-Costa-Rica

Copy link
Copy Markdown

Two things in mail batch we ran into while running this branch in production against Proton Bridge.

1. permanent is not wired through on delete. batchOp has no permanent field, and executeBatchOp calls DeleteMessages(mailbox, op.UIDs, false). Since mail delete --permanent exists as a flag outside batch, the same delete behaves differently depending on which path issues it. Our pipeline had been sending {"op":"delete","permanent":true} for some time believing those were permanent, while the messages were going to Trash.

2. That was silent, because unknown keys are dropped. decodeBatchOps uses a plain json.Unmarshal, so anything not on the struct is discarded without error:

$ echo '[{"op":"label","uids":["uid:99999999"],"label":"UNSORTED","bogus_unknown_key":true,"permanent":true}]' | pm-cli mail batch --json
{"results":[{"op":"label","success":false,"error":"no messages matched the given ID(s) in INBOX"}],"total":1,"succeeded":0,"failed":1}

Both keys accepted, neither honored. A json.Decoder with DisallowUnknownFields() would turn that into a parse-time error before any IMAP command runs, which fits the validate-everything-up-front approach already in MailBatchCmd.Run.

3. Minor: batchResult carries op but not the uids it answers for, so a caller pairing results back to inputs has to rely on array position. Echoing the uids would make that unambiguous.

Happy to send a PR for any of these if useful.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants