Ratmail Docs

Complete Guide

Install, onboard, configure, operate the TUI, automate with the CLI, and secure agent access with signed ACL policy.

Install

Ratmail is distributed as a Rust binary and is easiest to install directly from the GitHub repository. The install command builds and locks dependency versions for reproducible output.

Install from GitHub with Cargo:

cargo install --git https://github.com/peter-fm/ratmail.git --locked

After install, verify your binary is reachable in $PATH and check command help if needed:

ratmail --help

Run:

ratmail

First run auto-creates:

  • ~/.config/ratmail/ratmail.toml (or $XDG_CONFIG_HOME/ratmail/ratmail.toml)
  • ~/.config/ratmail/.setup-complete after setup completion

Keep ratmail.toml private. It can contain IMAP/SMTP credentials and should not be committed to source control.

Run from source in the app repo:

cargo run -p ratmail

From-source runs are useful when iterating on Ratmail internals, trying unreleased behavior, or validating changes to local ACL/CLI flows before publishing docs.

Onboarding Setup

The setup wizard is the fastest way to get a valid account config and safe baseline ACL policy in one pass. It is designed for first-run and for incrementally adding additional accounts later.

Run interactive setup:

ratmail setup

The wizard flow includes:

  • Provider pick: Gmail, Proton Bridge, Yahoo Mail, or custom IMAP/SMTP
  • Account form (name, email/username, password, display name, provider hosts/ports)
  • Optional multi-account add
  • Optional AI CLI enablement
  • ACL scope selection: one/many/all accounts
  • ACL options: body read, attachment download, send, message changes

Generated defaults for each account:

  • db_path = "ratmail-<slug>.db"
  • imap.initial_sync_days = 90
  • imap.fetch_chunk_size = 10

If AI CLI is enabled, setup writes:

  • [cli] defaults and policy public key path into ratmail.toml
  • policy draft to ~/.config/ratmail/cli-policy.toml

Setup intentionally keeps AI access conservative by default. Even if CLI is enabled, your signed policy controls what is actually allowed at runtime.

Apply policy with admin privileges:

sudo ratmail lock

That final admin step signs and applies policy to the system path, updates anti-rollback state, and ensures normal users or agents cannot silently replace policy.

For automated environments, ratmail setup --apply-system-policy can trigger the policy apply step directly, but still requires admin privileges.

Config Reference

Ratmail merges behavior from TOML config plus runtime defaults. If a key is omitted, Ratmail falls back to built-in safe values for that section.

Ratmail checks config paths in this order:

  1. ./ratmail.toml
  2. $XDG_CONFIG_HOME/ratmail/ratmail.toml (or ~/.config/ratmail/ratmail.toml)

Accounts

Each [[accounts]] entry is an independently addressable mailbox with its own database file. Multi-account tabs in the TUI map directly to this list.

[[accounts]]
name = "Personal"
db_path = "ratmail-personal.db"

[accounts.imap]
host = "imap.example.com"
port = 993
username = "user@example.com"
password = "app-password"
skip_tls_verify = false
initial_sync_days = 90
fetch_chunk_size = 10

[accounts.smtp]
host = "smtp.example.com"
port = 587
username = "user@example.com"
password = "app-password"
from = "Your Name <user@example.com>"
skip_tls_verify = false

Notes:

  • Relative db_path resolves under $XDG_STATE_HOME/ratmail (or ~/.local/state/ratmail)
  • If db_path is omitted, default is ratmail-<slug-account-name>.db
  • imap.fetch_chunk_size is clamped to 1..50

Operational guidance: keep initial_sync_days moderate for first sync speed, then use backfill from the TUI (o) as needed for older history.

Render

Render settings control HTML-to-terminal image behavior. In rendered mode, Ratmail chooses geometry based on terminal dimensions and these values.

  • render.remote_images: bool, default true
  • render.width_px: default 800 (runtime geometry can override)
  • render.render_scale: default 1.5, clamped 0.25..4.0
  • render.tile_height_px_side: default 1000
  • render.tile_height_px_focus: default 60

If your terminal does not support image protocols (Kitty/Sixel), Ratmail still works in text mode and falls back gracefully.

Send

Send settings affect outgoing message formatting and generated HTML alternatives when sending from compose or CLI.

  • send.html: default true
  • send.font_family: default Arial, sans-serif
  • send.font_size_px: default 14, clamped 8..72

If you want plainest output for compatibility-sensitive recipients, set send.html = false.

UI

UI values tune layout density and interaction style. Theme normalization is strict; unknown names fall back to default.

  • ui.folder_width_cols: default 25, clamped 8..40
  • ui.compose_vim: default false
  • ui.theme presets: default, ratmail, nord, gruvbox, solarized-dark, solarized-light, dracula, catppuccin-mocha, catppuccin-latte, custom

Custom palette keys ([ui.palette]):

base_fg, base_bg, border, bar_fg, bar_bg, accent, warn, error, selection_bg, selection_fg, link, muted

Custom palette values must be hex colors (for example #88c0d0). Invalid color strings are ignored for the specific palette key.

Spell

Spellcheck is backed by Hunspell dictionaries. You can control language and custom dictionary path here.

  • spell.lang: default en_US
  • spell.dir: optional dictionary directory
  • spell.ignore: list of words, normalized to lowercase

Use spell.ignore for recurring names, project terms, or acronyms that should not generate review noise during compose.

CLI

CLI configuration is split between enablement in ratmail.toml and signed policy content in the blob file. Both are required for active CLI operations.

  • cli.enabled: default false
  • cli.default_account: optional default CLI account
  • cli.policy.public_key_path: required when CLI enabled
  • cli.policy.path: signed blob path override
  • cli.policy.state_path: anti-rollback state path override

If cli.enabled = true but policy verification fails, Ratmail disables CLI execution and returns a JSON error explaining why.

TUI Guide

The TUI is optimized around quick keyboard workflows: browse folders, triage messages, open focused view, and compose without leaving the terminal.

Main modes:

  • List/View panes
  • Focus mode for full message scrolling
  • Compose mode
  • Overlays: search, links, attachments, spellcheck, bulk actions, confirmations

Primary keys

The help bar in-app shows compact bindings by default and expands with ?. Most list navigation works in both Vim-style and arrow-key style.

  • Tab, h, l: move focus panes
  • j/k: move selection
  • Space: select message and advance
  • Enter: open message / open selected bulk actions
  • v: toggle rendered/text view
  • p: toggle preview pane
  • /: search overlay
  • s: sync selected folder
  • o: backfill older messages
  • [/]: switch account tab
  • ?: toggle expanded help
  • q: quit

Behavior note: selecting with Space enables bulk actions. Press Enter with a selection set to open bulk action overlay.

Compose

Compose supports attachments, spell tools, reply/forward helpers, and draft confirmation. Sending can be triggered from keyboard without leaving the compose overlay.

  • Ctrl+S or F5: send
  • Ctrl+A: attach file picker
  • Ctrl+R: remove last attachment
  • F7: spellcheck overlay
  • Ctrl+Q or Esc: close compose (draft confirm if content exists)

Vim compose mode (ui.compose_vim = true):

  • Body starts in Normal mode, Esc toggles Insert/Normal
  • Normal mode supports movement/edit ops (h j k l w b 0 $ x dd, i a A I o O)

When Vim compose mode is off, compose behaves as a standard text-input workflow with tab-cycle focus.

Search syntax

Search accepts mixed plain text and structured field filters in one query. Filters narrow results before rendering message lists.

  • Text terms: match from, subject, and preview
  • from:, subject:, to:, date:
  • since:, before: (dateparse-compatible dates)
  • att:, file:, filename: for attachment names
  • type:, mime: for attachment MIME or extension

Examples:

from:alice subject:invoice since:2026-01-01
to:team@example.com att:report type:pdf
urgent deploy rollback

CLI Guide

The CLI is designed for agent/tool automation. Every response is machine-readable JSON with explicit success or failure fields.

CLI output is JSON, with schema ratmail.cli.v1.

{
  "schema": "ratmail.cli.v1",
  "ok": true,
  "result": { ... }
}

Errors:

{
  "schema": "ratmail.cli.v1",
  "ok": false,
  "error": "..."
}

Command tree

Read-only commands and mutation commands share one command tree. Actual permission to execute a command is determined by policy mode plus ACL allow/deny rules.

ratmail setup [--apply-system-policy]
ratmail lock
ratmail accounts list
ratmail folders list [--account <name>]
ratmail messages list [filters...]
ratmail message get --id <n> [--body] [--raw] [--attachments] [--fetch]
ratmail message body --id <n> [--fetch]
ratmail message raw --id <n> [--fetch]
ratmail message attachment-save --id <n> --index <i> --path <file> [--fetch]
ratmail message move --id <n> --folder <name>
ratmail message delete --id <n>
ratmail message mark --id <n> (--read|--unread)
ratmail sync [--account <name>] [--folder <name>] [--backfill] [--days <n>] [--wait] [--timeout-secs <n>]
ratmail send --to ... --subject ... --body ... [--cc ...] [--bcc ...] [--attach ...] [--wait] [--timeout-secs <n>]
ratmail acl edit|sign|apply ...

--wait on send and sync blocks for completion events up to --timeout-secs. Without --wait, commands queue work and return quickly.

Message list filters

  • --unread, --limit, --folder, --account
  • --from, --subject, --to, --date
  • --query with search syntax above
  • --since/--before or --since-ts/--before-ts
  • --att and --att-type attachment filters

For best performance in automation, pass folder/account explicitly and keep --limit small on polling loops.

Automation shortcut

Use string commands with --cmd, for example:

ratmail --cmd "messages list --account Personal --unread --limit 20"

--cmd is parsed by Ratmail and then re-routed through normal command handling, so ACL checks are identical to direct subcommands.

Agent Skills (Claude and Codex)

Ratmail ships skill assets under skills/ in the app repo. These are prompt/workflow packs meant for agent tooling, not binary plugins loaded by Ratmail itself.

Direct GitHub sources:

Install for Codex/OpenAI-style skills

If your Codex environment reads skills from $CODEX_HOME/skills, fetch directly from GitHub. For default local setups, use ~/.codex/skills:

mkdir -p "$HOME/.codex/skills/openai/ratmail-cli/agents"
curl -L "https://raw.githubusercontent.com/peter-fm/ratmail/main/skills/openai/ratmail-cli/SKILL.md" \
  -o "$HOME/.codex/skills/openai/ratmail-cli/SKILL.md"
curl -L "https://raw.githubusercontent.com/peter-fm/ratmail/main/skills/openai/ratmail-cli/agents/openai.yaml" \
  -o "$HOME/.codex/skills/openai/ratmail-cli/agents/openai.yaml"

Verify:

ls -R "$HOME/.codex/skills/openai/ratmail-cli"

Install for Claude-style skills

Claude clients vary by host/editor. If your setup supports a local filesystem skill folder, fetch the same way:

mkdir -p "$HOME/.claude/skills"
mkdir -p "$HOME/.claude/skills/ratmail-cli"
curl -L "https://raw.githubusercontent.com/peter-fm/ratmail/main/skills/claude/ratmail-cli/SKILL.md" \
  -o "$HOME/.claude/skills/ratmail-cli/SKILL.md"

If your Claude client uses a different path, copy the same ratmail-cli folder into that client-specific skills directory.

Usage note

These skills describe how an agent should operate the Ratmail CLI. They do not bypass Ratmail ACL policy. All real command permissions are still enforced by your signed CLI policy at runtime.

The published skill files are aligned with the signed-policy CLI model.

ACL and Policy

When [cli].enabled = true, Ratmail does not trust ACL values inline in ratmail.toml.

It requires a signed policy blob verified against [cli.policy].public_key_path.

This separation is intentional: local user config can remain easy to edit, while enforcement-critical policy is signed and promoted through an explicit privileged workflow.

Policy mode

  • readonly: no mutations; restricted fields unless explicitly allowed
  • readonly-full-access: read all fields including body/raw/attachments
  • full-access: allows mutations unless ACL flags/command rules deny

ACL fields

accounts, folders, from_allow, fields, allow_body, allow_raw, allow_attachments, allow_commands, deny_commands, allow_move, allow_delete, allow_mark, allow_send.

Pattern matching supports wildcard * (case-insensitive).

Rule precedence is deny-first for commands: if a command matches a deny pattern, it is blocked even if an allow pattern is broad.

In readonly, mutation commands are blocked regardless of allow lists. In full-access, mutation still depends on ACL toggles like allow_send and allow_delete.

Command IDs for allow/deny

accounts.list, folders.list, messages.list, message.get, message.body, message.raw, message.attachment.save, message.move, message.delete, message.mark, sync, send.

Signed policy workflow

  1. Draft/edit TOML policy (ratmail acl edit or setup-generated draft)
  2. Sign policy: ratmail acl sign --policy-toml ... --secret-key ... --out ...
  3. Apply policy: ratmail acl apply --policy ...
  4. Or use sudo ratmail lock to auto-sign and apply from draft

Policy versions should increase monotonically. Applying an older version is rejected by anti-rollback state unless you explicitly allow downgrade in manual apply flow.

ratmail lock also prints a human-readable review comparing current and incoming risky permissions before confirmation.

Default system paths:

  • Linux policy blob: /etc/ratmail/config.blob
  • macOS policy blob: /Library/Application Support/ratmail/config.blob
  • Linux public key: /etc/ratmail/policy-public.pem
  • macOS public key: /Library/Application Support/ratmail/policy-public.pem
  • Linux private key: /var/lib/ratmail/keys/policy-private.pem
  • macOS private key: /Library/Application Support/ratmail/keys/policy-private.pem
  • Linux state file: /var/lib/ratmail/cli-policy-state.json
  • macOS state file: /Library/Application Support/ratmail/cli-policy-state.json

These defaults can be overridden in [cli.policy] for custom deployment layouts.

Security Model

Ratmail CLI hardening is local-policy enforcement for agent workflows on a single machine. It reduces risk, but does not replace endpoint hardening or server-side controls.

  • Policy signatures are verified with OpenSSL Ed25519.
  • Policy versions are monotonic; rollback is rejected when version decreases.
  • ratmail lock requires root/admin privileges.
  • ACL is meaningful for non-privileged agents; root-level compromise can bypass local controls.

Operationally, keep agent processes unprivileged and treat any request for privileged escalation as a manual review checkpoint.

Troubleshooting

Most CLI failures are configuration or policy state issues. Start by checking that config paths, key paths, and policy version are all aligned.

  • CLI disabled: set [cli].enabled = true and configure signed policy + public key path.
  • Missing public key: ensure [cli.policy].public_key_path exists and is readable.
  • Policy verification failed: re-sign policy with matching private/public key pair.
  • Rollback detected: increase policy version before applying.
  • Attachment/body unavailable in CLI: allow the related ACL flags and command IDs.
  • No rendered HTML: terminal image protocol support is required for rendered mode.

If needed, rerun setup to regenerate defaults, then re-apply policy with sudo ratmail lock to restore a known-good baseline.