aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorElvis Claros Castro <elvis@claros.ar>2026-09-26 18:47:40 -0300
committerElvis Claros Castro <elvis@claros.ar>2026-09-26 18:47:40 -0300
commitd9738b4be2add82ff955f061c79316b0dc91768f (patch)
treee0f31bb9f72dff315fc475f9e9f30322b69602ff /README.md
downloadposta-d9738b4be2add82ff955f061c79316b0dc91768f.tar.gz
posta-d9738b4be2add82ff955f061c79316b0dc91768f.zip
posta: generic IMAP/SMTP mail CLI with JSON outputHEADmain
Diffstat (limited to 'README.md')
-rw-r--r--README.md126
1 files changed, 126 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e57ddb9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,126 @@
+# posta
+
+> *[Leé esto en castellano](README.es.md)*
+
+**posta** is a tiny, generic IMAP/SMTP mail client for your terminal. One
+binary, JSON output by default, and named accounts in a single TOML file —
+so your mailbox is as scriptable as any other API.
+
+The name comes from the *postas*: the relay stations of the colonial mail
+routes of South America. In Argentine slang, *la posta* also means
+"the real thing".
+
+```console
+$ posta list --unread --max 3 --format table
+ UID DATE FROM SUBJECT
+ 7121 ● Fri, 17 Jul 2026 17:0… "Example ISP" <billing@isp.ex… Your invoice is ready
+ 7120 ● Fri, 17 Jul 2026 15:0… Meetup <events@meetup.examp… 🚀 Registration open
+ 7119 ● Fri, 17 Jul 2026 10:1… "bank@example.com" Card notice
+
+$ posta search 'FROM bank UNSEEN' | jq .uids
+[7119, 7118, 7117]
+```
+
+## Features
+
+- **Works with any provider** — plain IMAP/SMTP with STARTTLS (`imap://`,
+ `smtp://`) or implicit TLS (`imaps://`, `smtps://`). Your own server,
+ Gmail, Fastmail, anything.
+- **Multiple accounts** — named accounts in one config file, switched with
+ `--account`, `$POSTA_ACCOUNT`, or a `default_account`.
+- **Script-friendly** — every command prints pretty JSON (pipe it to `jq`),
+ with `--format table` for humans.
+- **Secrets your way** — literal passwords (the file is checked for loose
+ permissions and posta warns you) or `password_cmd` to fetch them from
+ `pass`, a keyring, or any command.
+- **Safe by default** — reading never marks messages as seen
+ (`BODY.PEEK` everywhere); opt in with `--mark-read` or `posta mark read`.
+- **No config file needed** — everything can come from `POSTA_*` environment
+ variables, handy for CI and one-off scripts.
+
+## Install
+
+```sh
+git clone https://git.all.ar/pub/posta.git
+cd posta
+cargo install --path .
+```
+
+## Configure
+
+`~/.config/posta/config.toml` (or `$POSTA_CONFIG`, or `--config FILE`):
+
+```toml
+default_account = "personal"
+
+[accounts.personal]
+email = "alice@example.com"
+display_name = "Alice Example"
+imap_url = "imap://alice@example.com@mail.example.com:143"
+smtp_url = "smtp://alice@example.com@mail.example.com:587"
+password_cmd = "pass show mail/personal" # or: password = "..." (chmod 600!)
+
+[accounts.work]
+email = "alice@work.example"
+imap_url = "imaps://alice@imap.work.example" # implicit TLS, port 993
+smtp_url = "smtps://alice@smtp.work.example" # implicit TLS, port 465
+password_cmd = "secret-tool lookup mail work"
+sent_folder = "Sent Items"
+trash_folder = "Deleted"
+```
+
+The user part of a URL may itself contain `@`
+(`imap://alice@example.com@mail.example.com`); the host starts after the
+*last* one. `imap_password[_cmd]` / `smtp_password[_cmd]` override the shared
+password per protocol when they differ.
+
+Environment variables override any field of the selected account:
+`POSTA_IMAP_URL`, `POSTA_SMTP_URL`, `POSTA_PASSWORD`, `POSTA_PASSWORD_CMD`,
+`POSTA_IMAP_PASSWORD`, `POSTA_SMTP_PASSWORD`, `POSTA_EMAIL`,
+`POSTA_DISPLAY_NAME`, `POSTA_SENT_FOLDER`, `POSTA_TRASH_FOLDER`,
+plus `POSTA_ACCOUNT` and `POSTA_CONFIG`.
+
+## Use
+
+```sh
+posta accounts # configured accounts
+posta status # message/unread counts
+posta folders # list mailboxes
+posta list --unread # newest first
+posta list --query 'FROM bank SINCE 1-Jul-2026'
+posta get 7119 # headers + text body, as JSON
+posta get 7119 --html # prefer the HTML part
+posta get 7119 --raw > msg.eml # raw RFC 822 source
+posta send --to bob@example.com --subject 'Hi' --body 'Hello!'
+git log | posta send --to bob@example.com --subject 'Changelog'
+posta mark read 7119 7120 # also: unread, flagged, unflagged
+posta move 7119 --to Archives
+posta delete 7119 # moves to the trash folder
+posta search 'FROM bank UNSEEN' # raw IMAP SEARCH, prints UIDs
+```
+
+Global flags: `--account/-a NAME`, `--config FILE`,
+`--format json|table`, and `--folder` on folder-scoped commands.
+
+Every command opens a fresh session and logs out; there is no daemon,
+cache, or local state.
+
+## Notes
+
+- `send` appends a copy to the sent folder over IMAP (skip with
+ `--no-record`).
+- `move`/`delete` use `UID MOVE` when the server supports it, falling back
+ to `COPY` + `\Deleted` + `EXPUNGE`.
+- TLS is always required; plain-text connections are not supported.
+
+## Development
+
+```sh
+cargo test # unit + CLI integration tests, no server needed
+cargo clippy --all-targets -- -D warnings
+cargo fmt --check
+```
+
+## License
+
+[MIT](LICENSE)