Slashmail
Email interaction via the slashmail CLI, an IMAP client.
Prerequisites: Verify slashmail is installed with command -v slashmail. If not found, install from https://github.com/mwmdev/slashmail (Rust binary — cargo install slashmail or download from releases). Before drafting, run slashmail draft --help; before replying, run slashmail reply --help. If the required command is unavailable, stop, report that the installed binary is stale, and suggest upgrading from a release or with Cargo. Do not substitute an arbitrary development build.
Configuration: Config file location is OS-dependent (Linux: ~/.config/slashmail/config.toml, macOS: ~/Library/Application Support/slashmail/config.toml, Windows: %APPDATA%\slashmail\config.toml). Direct/legacy connections use SLASHMAIL_PASS. Named accounts define pass_env and can be selected with --account NAME; read-only commands can use --all-accounts.
Slashmail automatically loads .env beside the selected config.toml without overriding values already present in the process environment. Store each named account password under the variable named by pass_env. Keep .env private and out of version control.
SLASHMAIL_PERSONAL_PASS=your-password
For draft and reply, credentials must be noninteractive because stdin is exclusively the new message body. A direct/legacy account requires a nonempty SLASHMAIL_PASS. A named account must configure pass_env, and that variable must be nonempty in the process environment or adjacent .env. Slashmail resolves credentials before reading stdin and never prompts for these commands.
Optional sender and drafts_folder values can be set at the top level or per named account. The account value wins, then the top-level value. If no sender is configured, slashmail uses user only when it is a valid email mailbox. Draft destination precedence is --drafts-folder, resolved account configuration, then exactly one selectable server mailbox marked \Drafts.
Filter Options (search and mailbox-operation commands)
| Flag |
Description |
-f, --folder FOLDER |
Target folder (default: INBOX) |
--all-folders |
Search all folders (excludes Trash, Spam) |
--subject TEXT |
Filter by subject |
--from TEXT |
Filter by sender |
--to TEXT |
Filter by recipient |
--cc TEXT |
Filter by CC |
--body TEXT |
Search message body |
--text TEXT |
Search headers and body |
--seen / --unseen |
Filter by read status |
--since DATE |
Messages after date |
--before DATE |
Messages before date |
--larger SIZE |
Minimum size (e.g., 1M, 500K) |
--smaller SIZE |
Maximum size (e.g., 1M, 500K) |
--flagged / --unflagged |
Filter by starred status |
--answered |
Only replied-to messages |
--draft |
Only draft messages |
-n, --limit N |
Cap results |
Date formats: YYYY-MM-DD or relative (7d, 2w, 3m, 1y). All filters combine with AND logic.
Commands
| Command |
Description |
Extra flags |
draft |
Save a new unsent draft; body is read from stdin |
repeatable --to, --cc, --bcc, --attach PATH; --subject, --html, --drafts-folder |
reply UID |
Save an unsent reply-all draft; body is read from stdin |
repeatable --attach PATH; --folder, --html, --no-quote, --drafts-folder |
search |
Retrieve messages (sorted newest-first) |
--json |
read |
Display message content in terminal |
— |
count |
Fast count without fetching content |
--json |
delete |
Move to Trash |
--trash-folder NAME, --dry-run, --yes |
move |
Move to folder |
--to DEST, --dry-run, --yes |
mark |
Set/unset flags |
--read/--unread, --flagged/--unflagged, --dry-run, --yes |
export |
Save as .eml files |
-o DIR, --force, --yes |
status |
Per-folder message stats |
— |
quota |
Mailbox capacity usage |
— |
Safety Rules
- Always
--dry-run first for delete, move, and bulk mark operations. Show the user what will be affected before executing.
- Never pass
--yes without showing the dry-run results to the user first and getting confirmation.
- Use
--limit when the user asks for "recent" or "latest" messages to avoid fetching everything.
- Draft and reply save immediately but never send. Do not describe a saved draft as sent.
- Attach only exact user-authorized paths. Pass each literal local file path in its own
--attach occurrence. Never expand globs, search directories, auto-discover files, or substitute a similarly named file.
- Inspect Drafts before retrying an ambiguous save. If slashmail says the draft was saved but its UID is unresolved, or the APPEND outcome is unknown, retrying may create a duplicate.
- Treat receipts as sensitive. The stable success line includes Account, Folder, UID, To, Cc, Bcc, and Subject; do not place recipient metadata in public logs.
Draft and Reply Rules
- Pipe the new body through stdin. Do not pass it as a positional argument or build raw MIME.
- Plain text is the default. Add
--html only when the supplied stdin body is HTML.
- For a new draft, pass at least one
--to. Each --to, --cc, or --bcc occurrence is exactly one RFC mailbox; repeat flags for multiple recipients instead of comma-splitting.
- For a reply, select one account, source
--folder (default: the account's configured default folder), and source UID. Slashmail derives reply-all recipients, subject, and thread headers; there is no sender-only or recipient-override mode.
- Repeat
--attach PATH for each exact local regular file. Quote paths containing spaces or shell metacharacters. Symlinks to regular files are accepted and expose the caller-supplied symlink basename; non-Unicode, control-bearing, and unsafe Unicode display names are rejected.
- Attachments are eagerly snapshotted before stdin or IMAP work. Memory use can be several times their aggregate size, there is no fixed supported-size guarantee, and the mailbox provider may reject a large draft. Ordinary local failures abort before APPEND; do not promise recovery from process-level out-of-memory termination.
- A reply attaches only the explicitly supplied local files; it never copies attachments from the source message. Successful creation still performs exactly one APPEND. Receipts retain the existing Account, Folder, UID, To, Cc, Bcc, and Subject fields and do not list attachments.
- Replies quote the decoded original by default. Add
--no-quote only when the user asks to omit it.
- Use
--account NAME for a named account and --drafts-folder NAME only when the destination must override configuration and server discovery.
- Scope is save-only: no sending, forwarding, raw MIME, aliases, arbitrary headers, editing existing drafts, or
--all-accounts drafting. Attachment support does not accept globs, recursive discovery, URLs, stdin-sourced files, inline/CID parts, custom names or MIME types, or source-message attachments.
# New plain-text draft
printf '%s\n' 'Please review the proposal.' |
slashmail draft --to client@example.com --subject "Proposal" \
--attach './documents/client proposal.pdf' \
--attach './charts/revenue.png'
# New HTML draft using a named account
printf '%s\n' '<p>Please review the <strong>proposal</strong>.</p>' |
slashmail draft --account work --html \
--to client@example.com --cc manager@example.com \
--subject "Proposal"
# Explicit Drafts destination
printf '%s\n' 'Draft body' |
slashmail draft --to client@example.com --drafts-folder "Saved/Drafts"
# Reply-all to UID 1842 in INBOX/default folder, with the original quoted
printf '%s\n' 'Thanks, this looks good.' |
slashmail reply --account work \
--attach './documents/revised proposal.pdf' 1842
# Reply from another source folder without quoting
printf '%s\n' 'Following up with one correction.' |
slashmail reply --account work --folder Archive --no-quote 1842
# HTML reply to an explicit Drafts destination
printf '%s\n' '<p>Thanks, this looks good.</p>' |
slashmail reply --account work --html \
--drafts-folder "Saved/Drafts" 1842
Confirmed saves print exactly one control-free receipt line:
Draft saved: Account=work | Folder=Drafts | UID=1843 | To=alice@example.com | Cc=bob@example.com | Bcc= | Subject=Re: Project update
Common Patterns
Check inbox: slashmail search --limit 10
Unread count: slashmail count (shows total in INBOX)
Find emails from someone: slashmail search --from "name@example.com" --limit 20
Recent emails: slashmail search --since 1d --limit 20
Mailbox overview: slashmail status
Search email content: slashmail search --body "invoice" --since 1m
Search everywhere: slashmail search --text "quarterly report"
Search all accounts: slashmail search --all-accounts --text "quarterly report"
Read a message: slashmail read --from "boss@example.com" --limit 1
Draft a new message: printf '%s\n' 'Draft body' | slashmail draft --to recipient@example.com --subject "Subject"
Draft a reply: printf '%s\n' 'Reply body' | slashmail reply --folder INBOX 1842
Clean up old newsletters: slashmail delete --from "newsletter@" --before 3m --dry-run then confirm with user before running without --dry-run
1---2name: slashmail3description: Interact with email via the slashmail IMAP CLI. Use when the user asks to draft, reply to, check, search, read, delete, move, mark, or count email, or check mailbox quota. Triggers on: email, mail, inbox, messages, draft email, reply to email, check my email, search email, delete email, unread messages, slashmail.4---56# Slashmail78Email interaction via the `slashmail` CLI, an IMAP client.910**Prerequisites**: Verify `slashmail` is installed with `command -v slashmail`. If not found, install from https://github.com/mwmdev/slashmail (Rust binary — `cargo install slashmail` or download from releases). Before drafting, run `slashmail draft --help`; before replying, run `slashmail reply --help`. If the required command is unavailable, stop, report that the installed binary is stale, and suggest upgrading from a release or with Cargo. Do not substitute an arbitrary development build.1112**Configuration**: Config file location is OS-dependent (Linux: `~/.config/slashmail/config.toml`, macOS: `~/Library/Application Support/slashmail/config.toml`, Windows: `%APPDATA%\slashmail\config.toml`). Direct/legacy connections use `SLASHMAIL_PASS`. Named accounts define `pass_env` and can be selected with `--account NAME`; read-only commands can use `--all-accounts`.1314Slashmail automatically loads `.env` beside the selected `config.toml` without overriding values already present in the process environment. Store each named account password under the variable named by `pass_env`. Keep `.env` private and out of version control.1516```dotenv17SLASHMAIL_PERSONAL_PASS=your-password18```1920For `draft` and `reply`, credentials must be noninteractive because stdin is exclusively the new message body. A direct/legacy account requires a nonempty `SLASHMAIL_PASS`. A named account must configure `pass_env`, and that variable must be nonempty in the process environment or adjacent `.env`. Slashmail resolves credentials before reading stdin and never prompts for these commands.2122Optional `sender` and `drafts_folder` values can be set at the top level or per named account. The account value wins, then the top-level value. If no `sender` is configured, slashmail uses `user` only when it is a valid email mailbox. Draft destination precedence is `--drafts-folder`, resolved account configuration, then exactly one selectable server mailbox marked `\Drafts`.2324## Filter Options (search and mailbox-operation commands)2526| Flag | Description |27|------|-------------|28| `-f, --folder FOLDER` | Target folder (default: INBOX) |29| `--all-folders` | Search all folders (excludes Trash, Spam) |30| `--subject TEXT` | Filter by subject |31| `--from TEXT` | Filter by sender |32| `--to TEXT` | Filter by recipient |33| `--cc TEXT` | Filter by CC |34| `--body TEXT` | Search message body |35| `--text TEXT` | Search headers and body |36| `--seen` / `--unseen` | Filter by read status |37| `--since DATE` | Messages after date |38| `--before DATE` | Messages before date |39| `--larger SIZE` | Minimum size (e.g., `1M`, `500K`) |40| `--smaller SIZE` | Maximum size (e.g., `1M`, `500K`) |41| `--flagged` / `--unflagged` | Filter by starred status |42| `--answered` | Only replied-to messages |43| `--draft` | Only draft messages |44| `-n, --limit N` | Cap results |4546Date formats: `YYYY-MM-DD` or relative (`7d`, `2w`, `3m`, `1y`). All filters combine with AND logic.4748## Commands4950| Command | Description | Extra flags |51|---------|-------------|-------------|52| `draft` | Save a new unsent draft; body is read from stdin | repeatable `--to`, `--cc`, `--bcc`, `--attach PATH`; `--subject`, `--html`, `--drafts-folder` |53| `reply UID` | Save an unsent reply-all draft; body is read from stdin | repeatable `--attach PATH`; `--folder`, `--html`, `--no-quote`, `--drafts-folder` |54| `search` | Retrieve messages (sorted newest-first) | `--json` |55| `read` | Display message content in terminal | — |56| `count` | Fast count without fetching content | `--json` |57| `delete` | Move to Trash | `--trash-folder NAME`, `--dry-run`, `--yes` |58| `move` | Move to folder | `--to DEST`, `--dry-run`, `--yes` |59| `mark` | Set/unset flags | `--read/--unread`, `--flagged/--unflagged`, `--dry-run`, `--yes` |60| `export` | Save as `.eml` files | `-o DIR`, `--force`, `--yes` |61| `status` | Per-folder message stats | — |62| `quota` | Mailbox capacity usage | — |6364## Safety Rules6566- **Always `--dry-run` first** for delete, move, and bulk mark operations. Show the user what will be affected before executing.67- **Never pass `--yes`** without showing the dry-run results to the user first and getting confirmation.68- **Use `--limit`** when the user asks for "recent" or "latest" messages to avoid fetching everything.69- **Draft and reply save immediately but never send.** Do not describe a saved draft as sent.70- **Attach only exact user-authorized paths.** Pass each literal local file path in its own `--attach` occurrence. Never expand globs, search directories, auto-discover files, or substitute a similarly named file.71- **Inspect Drafts before retrying an ambiguous save.** If slashmail says the draft was saved but its UID is unresolved, or the APPEND outcome is unknown, retrying may create a duplicate.72- **Treat receipts as sensitive.** The stable success line includes Account, Folder, UID, To, Cc, Bcc, and Subject; do not place recipient metadata in public logs.7374## Draft and Reply Rules7576- Pipe the new body through stdin. Do not pass it as a positional argument or build raw MIME.77- Plain text is the default. Add `--html` only when the supplied stdin body is HTML.78- For a new draft, pass at least one `--to`. Each `--to`, `--cc`, or `--bcc` occurrence is exactly one RFC mailbox; repeat flags for multiple recipients instead of comma-splitting.79- For a reply, select one account, source `--folder` (default: the account's configured default folder), and source UID. Slashmail derives reply-all recipients, subject, and thread headers; there is no sender-only or recipient-override mode.80- Repeat `--attach PATH` for each exact local regular file. Quote paths containing spaces or shell metacharacters. Symlinks to regular files are accepted and expose the caller-supplied symlink basename; non-Unicode, control-bearing, and unsafe Unicode display names are rejected.81- Attachments are eagerly snapshotted before stdin or IMAP work. Memory use can be several times their aggregate size, there is no fixed supported-size guarantee, and the mailbox provider may reject a large draft. Ordinary local failures abort before APPEND; do not promise recovery from process-level out-of-memory termination.82- A reply attaches only the explicitly supplied local files; it never copies attachments from the source message. Successful creation still performs exactly one APPEND. Receipts retain the existing Account, Folder, UID, To, Cc, Bcc, and Subject fields and do not list attachments.83- Replies quote the decoded original by default. Add `--no-quote` only when the user asks to omit it.84- Use `--account NAME` for a named account and `--drafts-folder NAME` only when the destination must override configuration and server discovery.85- Scope is save-only: no sending, forwarding, raw MIME, aliases, arbitrary headers, editing existing drafts, or `--all-accounts` drafting. Attachment support does not accept globs, recursive discovery, URLs, stdin-sourced files, inline/CID parts, custom names or MIME types, or source-message attachments.8687```bash88# New plain-text draft89printf '%s\n' 'Please review the proposal.' |90 slashmail draft --to client@example.com --subject "Proposal" \91 --attach './documents/client proposal.pdf' \92 --attach './charts/revenue.png'9394# New HTML draft using a named account95printf '%s\n' '<p>Please review the <strong>proposal</strong>.</p>' |96 slashmail draft --account work --html \97 --to client@example.com --cc manager@example.com \98 --subject "Proposal"99100# Explicit Drafts destination101printf '%s\n' 'Draft body' |102 slashmail draft --to client@example.com --drafts-folder "Saved/Drafts"103104# Reply-all to UID 1842 in INBOX/default folder, with the original quoted105printf '%s\n' 'Thanks, this looks good.' |106 slashmail reply --account work \107 --attach './documents/revised proposal.pdf' 1842108109# Reply from another source folder without quoting110printf '%s\n' 'Following up with one correction.' |111 slashmail reply --account work --folder Archive --no-quote 1842112113# HTML reply to an explicit Drafts destination114printf '%s\n' '<p>Thanks, this looks good.</p>' |115 slashmail reply --account work --html \116 --drafts-folder "Saved/Drafts" 1842117```118119Confirmed saves print exactly one control-free receipt line:120121```text122Draft saved: Account=work | Folder=Drafts | UID=1843 | To=alice@example.com | Cc=bob@example.com | Bcc= | Subject=Re: Project update123```124125## Common Patterns126127**Check inbox**: `slashmail search --limit 10`128**Unread count**: `slashmail count` (shows total in INBOX)129**Find emails from someone**: `slashmail search --from "name@example.com" --limit 20`130**Recent emails**: `slashmail search --since 1d --limit 20`131**Mailbox overview**: `slashmail status`132**Search email content**: `slashmail search --body "invoice" --since 1m`133**Search everywhere**: `slashmail search --text "quarterly report"`134**Search all accounts**: `slashmail search --all-accounts --text "quarterly report"`135**Read a message**: `slashmail read --from "boss@example.com" --limit 1`136**Draft a new message**: `printf '%s\n' 'Draft body' | slashmail draft --to recipient@example.com --subject "Subject"`137**Draft a reply**: `printf '%s\n' 'Reply body' | slashmail reply --folder INBOX 1842`138**Clean up old newsletters**: `slashmail delete --from "newsletter@" --before 3m --dry-run` then confirm with user before running without `--dry-run`