Skip to content

Releases: 0xSMW/mail.app-cli

v3.2.0: Optional email sending restriction

Choose a tag to compare

@0xSMW 0xSMW released this 28 Oct 03:27
0db7e03

Mail.app CLI 3.2.0 adds an optional sending restriction for workflows where you want to read mail and prepare drafts without sending messages.

Disable sending

Save the restriction in your configuration:

mail-app-cli config set send.enabled false

Or disable sending for one invocation with the global flag:

mail-app-cli --no-send tui

The restriction covers send, drafts send, replies, reply-all, forwards, and sending from the TUI. Blocked CLI sends exit with status 1 and explain that email sending is disabled. The TUI keeps your composed text available to save as a draft.

Draft creation and management, reading mail, and dry-run previews remain available. Sending stays enabled by default. --no-send=false cannot override a stored restriction.

Use mail-app-cli config show to inspect the effective setting and its source. Restore the default with mail-app-cli config unset send.enabled, or explicitly enable sending with mail-app-cli config set send.enabled true.

Install or update

CGO_ENABLED=1 go install github.com/0xSMW/mail.app-cli/v3/cmd/mail-app-cli@v3.2.0

Requires macOS, Go 1.25 or newer, and Xcode Command Line Tools. Keep Automation and Full Disk Access enabled for the app running the CLI.

v3.1.0: Find email links and unsubscribe opportunities

Choose a tag to compare

@0xSMW 0xSMW released this 23 Oct 04:52
eff057a

Mail.app CLI 3.1.0 makes the destinations behind email links available directly in your terminal. Find the real URL behind “unsubscribe here,” inspect one message, or discover unsubscribe opportunities across whole folders.

Find unsubscribe opportunities

  • Use unsubscribe show MESSAGE_ID to inspect local mailing-list headers, HTML footer links, and plain-text unsubscribe or preference controls.
  • Use unsubscribe scan MAILBOX... to traverse entire folders, or add --all-accounts to include every enabled account.
  • Review results grouped by mailing-list identity, with provisional fallback groups clearly labeled. Exact destinations retain their source and message evidence, including controls found only in older messages.
  • Resume an interrupted or time-limited scan from its private checkpoint. Retry incomplete local sources when they become available, or restart for fresh observations.
  • See explicit coverage, pending work, and extraction exceptions. Recovered links remain available when a local source is partial or missing.

Access any email link

links MESSAGE_ID exposes labels and full destinations. Use show --links for links beside the message body, or consume structured link inventories from show and messages read. Personalized URL parameters and MIME source information are retained.

Discovery is read-only: it never opens or fetches destinations, sends mail, or changes subscriptions. Unsubscribe discovery inspects all supported local body alternatives without asking Mail to render or download missing content.

mail-app-cli unsubscribe show 100001 --json
mail-app-cli unsubscribe scan INBOX --all-accounts --json
mail-app-cli links 100001 --json

Install or update

CGO_ENABLED=1 go install github.com/0xSMW/mail.app-cli/v3/cmd/mail-app-cli@v3.1.0

Requires macOS, Go 1.25 or newer, and Xcode Command Line Tools. Keep Automation and Full Disk Access enabled for the app running the CLI.

v3.0.0: Native transport, Exchange support, and background Gmail Archive

Choose a tag to compare

@0xSMW 0xSMW released this 20 Oct 03:33
d482aa0

Mail.app CLI 3.0 sends typed Apple Events to Mail.app and reads Mail's local data through embedded SQLite. This reduces subprocess overhead and Mail rendering stalls. Exchange search, moves, and drafts are more reliable. Gmail Inbox Archive runs in a background viewer, so you can keep working while an agent archives. Connected Gmail accounts can manage labels. Existing commands and JSON schema version 1 remain compatible.

Native transport

  • Native is the default on macOS builds with cgo. Apple Events handle metadata, message changes, composition, rules, and signatures. Read-only embedded SQLite handles local lists and searches.
  • Bodies, headers, and attachments come from Mail's cached MIME when the cached copy is complete. Missing local content falls back to scoped Mail reads where supported.
  • --backend legacy or MAIL_APP_CLI_BACKEND=legacy selects the scripting backend, which non-cgo builds use automatically. Failed native changes never retry through legacy.

Exchange and search

  • Exchange mailboxes are recognized in Inbox and other folders, so search and cached content include previously missing messages.
  • Scoped reads recover from a lagging local index and confirm the requested account and mailbox.
  • Incomplete searches fail unless you request partial results.
  • Moves and archives stay verifiable when sync changes a local ID or size. Matching uses RFC message identity, account, sender, subject, and sent time. Ambiguous matches report as unverified.

Drafts and sending

  • On the native backend, compose, reply, reply all, and forward use Apple Events in the CLI and TUI and keep Mail's original message relationships. send and drafts create accept --reply-to, --reply-all, and --forward-of.
  • You can create, update, and send saved plain-text drafts with ordinary attachments. Recipients, blank paragraphs, Unicode filenames, and file contents are preserved.
  • Both backends record the draft before sending. After Mail acknowledges submission, they delete the draft only if it is unchanged. Uncertain sends are never resubmitted automatically. Acknowledgment does not confirm delivery, and Mail may normalize newlines in text attachments.
  • Drafts with custom formatting, inline content, signing, encryption, or reply headers stay in Mail.

Gmail

  • In 2.4, Gmail Inbox Archive opened a separate window. It now uses a background viewer with the preview hidden, on both backends. It never activates Mail, raises windows, or changes focus, and it closes only its own viewer. It stops before pressing if the message or button is missing or ambiguous, and it never repeats an uncertain archive.
  • New label commands connect through OAuth and store tokens in Keychain. They list labels and add or remove Important and existing custom labels, with dry runs, receipts, and verification against Gmail. A mismatched identity stops the change. Labels apply to Gmail only.

Upgrade and permissions

  • The module path is now github.com/0xSMW/mail.app-cli/v3, and the install script installs /v3.
  • Native source builds need macOS, Go 1.25 or newer, and Xcode Command Line Tools.
  • Grant Automation access to Mail and Full Disk Access to the app running the CLI. Gmail Inbox Archive also needs Accessibility access. mail-app-cli doctor reports access and the active backend.

Install

CGO_ENABLED=1 go install github.com/0xSMW/mail.app-cli/v3/cmd/mail-app-cli@v3.0.0

2.4.0 — Sender, drafts, and mailbox reliability

Choose a tag to compare

@0xSMW 0xSMW released this 14 Oct 03:07
0b35f7e

Mail.app CLI 2.4 improves sender selection, draft creation and sending, and repeatable mailbox cleanup.

Sending and drafts

  • Select a configured sender address with --from. Sending and draft creation check the account and sender before submitting or saving, preventing fallback to another account.
  • Create and send messages without the attachment-access error. File attachments use Mail’s native attachment operation, including Unicode filenames.
  • Find Drafts through Mail’s account-owned special mailbox references, including localized and nested folders.
  • Send supported plain-text drafts containing Mail’s standard compose headers. Rich-text, inline, threaded, signed, and encrypted drafts still require sending through Mail.
  • Verify saved drafts directly through Mail instead of waiting for the Envelope Index. Send receipts distinguish submission from pending original-draft cleanup; do not resend a message already marked submitted: true.

Mailbox cleanup and recovery

  • Gmail Inbox archives use Mail’s native Archive control. Grant Accessibility access to the application running the CLI; the operation briefly opens a separate Mail window and stops if it cannot confirm the intended message.
  • Verify final source, destination, and requested read state with bounded observation using --settle and --verify-budget.
  • Recheck saved archive/move receipts with messages reconcile receipt.json without repeating the mutation.
  • Use --mark-read-on-skip with --mark-read to explicitly mark an already-archived record read.
  • Synchronization requests target the selected account. Local counts and receipts describe Mail’s observed state, rather than guaranteeing server-side labels.

Reads and scans

  • Body extraction reports diagnostics for images, nontext parts, partial files, and MIME alternative selection. Request alternative text with --body-alternatives.
  • Save and resume cumulative mailbox traversal with messages scan --checkpoint /absolute/path/history.json; use --restart-checkpoint for a fresh scan.

Install

Requires macOS and Go 1.25 or newer:

go install github.com/0xSMW/mail.app-cli/v2/cmd/mail-app-cli@v2.4.0

2.3.0: Body reads from disk and paged scans

Choose a tag to compare

@0xSMW 0xSMW released this 29 Sep 11:38
20ff3a2

mail-app-cli 2.3 reads message bodies from the files Mail.app keeps on disk, so read and show no longer wait for Mail.app to render a body. A message that used to stall Mail.app no longer holds up the commands queued behind it. messages scan can now page through a mailbox of any size with a cursor, and verified archives and moves report what they found in the source and the destination. A few outputs change in ways a script can notice. They are listed under "Changes that can affect scripts".

Summary

  • messages read and show take the body from Mail.app's message file on disk and ask Mail.app only for metadata. Each result has contentSource, which is disk or mail. A message with no readable file falls back to Mail.app, and --body-source mail makes Mail.app render the body as before.
  • messages read items carry diagnostics with the time spent in each phase of the read. When a read times out, pending names the operation Mail.app had not answered and lastCompleted names the one before it.
  • messages scan takes --cursor and returns nextCursor. To read a mailbox to the end, repeat the same arguments with --cursor "$NEXT_CURSOR" until a result has no nextCursor. Pages run newest first, and each coverage entry reports exhausted and remaining. A cursor works only with the mailboxes and filters it was issued for, though --limit can change between pages.
  • Verified archive and move receipts carry observed with sourcePresent, destinationPresent, destinationRead, and the message's current local IDs in sourceIds and destinationIds. When Mail.app regenerates a Gmail message in INBOX after an archive, verifyStatus stays present_in_source and sourceIds holds the new ID to act on.
  • Mailbox lookup reads each level of the mailbox tree from Mail.app in one request instead of one mailbox at a time. Every command that resolves a mailbox through Mail.app is faster, mutations included.
  • list --with-content still asks Mail.app to render each body, so it can still stall. Read bodies with messages read or show.

Changes that can affect scripts

  • Body text read from disk can differ slightly from Mail.app's rendering. It uses the HTML part when there is one, drops elements styled display:none and > reply markers, keeps list markers, and leaves out the placeholder character Mail.app inserts for each inline image. It applies inline styles only, so spacing can differ where a stylesheet sets the layout. Pass --body-source mail to get Mail.app's text.
  • message not found now means Mail.app answered and the mailbox does not hold the ID. A Mail.app error during read or show used to be reported as not found. It now returns an error that names the phase where it happened.
  • A mailbox lookup that times out or loses its connection to Mail.app now reports that failure. It used to report the mailbox as missing.
  • messages scan --query used to stop at 50 results per mailbox and still report complete: true. Scan now applies --query and --unread before --limit and returns every match, one page at a time. A mailbox with more matches than --limit sets complete: false, exits 5, and returns a nextCursor to continue.

For direct Go installation, use:

go install github.com/0xSMW/mail.app-cli/v2/cmd/mail-app-cli@latest

2.2.1 — Draft attachments and installation fixes

Choose a tag to compare

@0xSMW 0xSMW released this 22 Sep 08:16
1c6d0dc
  • Attach files when creating or updating drafts with repeatable --attach flags.
  • Preserve existing attachments when editing a draft’s subject or body.
  • Wait for attachments to finish saving and retain the original draft if replacement verification fails.
  • Fix the installer and make install to produce the expected mail-app-cli executable.

For direct Go installation, use:

go install github.com/0xSMW/mail.app-cli/v2/cmd/mail-app-cli@latest

2.2.0 — Faster mail triage

Choose a tag to compare

@0xSMW 0xSMW released this 22 Sep 06:52
dae7553

mail-app-cli 2.2 makes daily mail triage faster, with multi-mailbox scans, selected-message reading, and quicker verified batches.

Summary

  • messages scan reads multiple mailboxes in one command, combines duplicate messages while retaining their mailbox membership, and reports incomplete coverage explicitly.
  • messages read retrieves the bodies of selected messages together. Successful reads remain available if another message fails or times out, with per-message errors and configurable time limits.
  • Compatible batch actions reuse a serial Mail.app connection to reduce repeated startup overhead while preserving durable receipts and recovery information.
  • Read and flag verification finishes as soon as the requested state is confirmed. Archive and delete retain their synchronization checks.
  • Updated workflow guidance helps agents scan metadata first, read only relevant bodies, and combine marking messages read with verified cleanup actions.

2.1.3

Choose a tag to compare

@0xSMW 0xSMW released this 01 Sep 06:47
17d9ea1

Summary

  • Verified mailbox actions stay responsive in very large Gmail mailboxes. An 18-message verified batch now completes in 7.18 seconds instead of 413 seconds—about 57× faster.
  • Archive confirmation is more trustworthy: success means a message remains available in All Mail and no longer appears in INBOX after synchronization settles.
  • Large batches can apply their requested actions without pausing for a long verification step after every message.
  • Interrupted commands stop their Mail.app automation promptly, so later commands do not queue behind abandoned work.
  • Durable receipts keep confirmed, uncertain, and incomplete outcomes distinct, making interrupted batches safer to recover.

2.1.2

Choose a tag to compare

@0xSMW 0xSMW released this 29 Aug 19:13
a95ba1c

Summary

  • Archive and move verification now waits through brief Mail and iCloud resync delays, preventing successful moves from being reported as failed.
  • Verification can find messages after Mail assigns them new local IDs, even when RFC Message-ID lookup temporarily fails.
  • Mutation receipts now keep applied moves separate from inconclusive destination verification, so moved counts remain accurate.
  • Timeout and cancellation outcomes remain clearly reported as unknown_after_timeout.

2.1.1

Choose a tag to compare

@0xSMW 0xSMW released this 29 Aug 05:25
9334090

Summary

  • Every message mutation now creates a durable receipt before changing Mail, so completed work remains recoverable if a command is interrupted or its output is lost.
  • --report-file keeps its existing JSON format and now includes a JSONL journal alongside it for per-step progress and recovery.
  • Archive and move verification now follows stable message identity when Mail assigns a new local ID, with clear confirmed, failed, and unknown outcomes.
  • Gmail archive now handles messages carrying both INBOX and Important correctly, removing the INBOX label without stripping Important.
  • smart list now reports Mail’s Today view from messages received since local midnight, including explicit total and unread counts.
  • Custom Smart Mailboxes that Mail does not expose through automation now return a clear unsupported result instead of a successful empty list.