aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: e57ddb976ec7f4a804f329957cc6d9f1e02b10c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
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)