A terminal-based email client with Vim-style modal keybindings, written in Go.
vimail brings the speed of Vim navigation to your inbox with a 3-pane layout, modal editing, and multiple color themes.
- Vim-style modal editing — Normal, Insert, Visual, and Command modes
- 3-pane layout — Mailbox sidebar, message list, and preview pane
- 8 color themes — vimail, tokyonight, catppuccin, kanagawa, gruvbox, nord, matrix, system
- Hot-swappable themes — Switch with
:theme <name>at any time - AI compose assistant —
:aiin the editor to draft or rewrite emails using any CLI agent - Compose with Vim — Full Vim keybindings in the message body editor
- Global search — Press
/to search across all accounts and folders - Multiple accounts — Manage several email accounts in one view
- Export to ZIP — Press
Eto export messages with text, HTML, metadata, and attachments - Attachments — View metadata in preview, save to disk with
S - Visual mode batch ops — Select messages with
v, then delete (d) or mark as read (r) - HTML email rendering — Clean text conversion via html2text, open raw HTML in browser with
o - JSON auto-format — Pretty-prints JSON bodies in the preview pane
- Incremental sync — Per-account IMAP sync with loading indicators
- Offline operation queue — Deletes, sends, and mark-read ops are queued in SQLite and retried on reconnect
- Pure Go — No CGO required, single static binary
- Go 1.24+
- A terminal with truecolor support (
COLORTERM=truecolor)
Grab the latest release from GitHub Releases — no Go required.
git clone https://github.com/gausejakub/vimail.git
cd vimail
go build -o vimail .Move the binary somewhere on your $PATH:
mv vimail ~/.local/bin/go install github.com/gausejakub/vimail@latestvimailIf built locally without moving to $PATH:
./vimailvimail launches in fullscreen (alt-screen) mode. Press q or :quit to exit.
- Add accounts to
~/.config/vimail/config.toml(see examples below) - Run
vimail setupto store credentials in your OS keyring
vimail setupThis walks through each configured account and securely stores your password in the OS keyring. If credentials already exist, it will ask before overwriting.
vimail reads its config from ~/.config/vimail/config.toml. If the file doesn't exist, defaults are used.
[general]
preview_pane = true
[theme]
name = "tokyonight"Gmail requires an app password (regular passwords don't work with IMAP):
- Enable 2-Factor Authentication at https://myaccount.google.com/security
- Generate an app password at https://myaccount.google.com/apppasswords
- Copy the 16-character code
- Add to config:
[[accounts]]
name = "Gmail"
email = "you@gmail.com"
imap_host = "imap.gmail.com"
imap_port = 993
smtp_host = "smtp.gmail.com"
smtp_port = 587
auth_method = "app-password"
tls = "tls"- Run
vimail setupand paste the 16-character app password when prompted
Most providers work with a regular password or app password:
[[accounts]]
name = "Personal"
email = "alice@example.com"
imap_host = "imap.example.com"
imap_port = 993
smtp_host = "smtp.example.com"
smtp_port = 587
auth_method = "plain" # "plain" | "app-password"
tls = "tls" # "tls" (default) | "starttls" | "none"Common provider settings:
| Provider | IMAP Host | IMAP Port | SMTP Host | SMTP Port |
|---|---|---|---|---|
| Gmail | imap.gmail.com | 993 | smtp.gmail.com | 587 |
| Outlook/Hotmail | outlook.office365.com | 993 | smtp.office365.com | 587 |
| Yahoo | imap.mail.yahoo.com | 993 | smtp.mail.yahoo.com | 587 |
| iCloud | imap.mail.me.com | 993 | smtp.mail.me.com | 587 |
| Seznam.cz | imap.seznam.cz | 993 | smtp.seznam.cz | 465 |
After adding accounts, run vimail setup to store credentials.
| Key | Action |
|---|---|
j / k |
Move down / up in current pane |
10j / 5k |
Move N lines down / up |
h / l |
Switch pane left / right |
gg / G |
Jump to top / bottom |
500gg / 500G |
Jump to line N |
Ctrl+D / Ctrl+U |
Half-page scroll (preview) |
Tab / Shift+Tab |
Next / previous pane |
| Key | Action |
|---|---|
c |
Compose new message |
r |
Reply to selected message |
f |
Forward |
dd |
Delete message |
S |
Save attachments to ~/Downloads |
E |
Export message(s) to ZIP |
o |
Open in browser |
R |
Refresh |
Enter |
Open draft (in Drafts folder) |
Ctrl+S |
Send message (in compose) |
Esc |
Close overlay / save draft / clear search |
/ |
Search all accounts and folders |
| Key | Action |
|---|---|
: |
Enter command mode |
v / V |
Enter visual mode (select range, d to delete, r to mark read) |
? |
Toggle help overlay |
q |
Quit |
| Command | Action |
|---|---|
:quit / :q |
Quit vimail |
:theme <name> |
Switch theme |
:sync |
Sync mail |
:ai |
AI-assisted compose (default agent) |
:ai <name> |
AI-assisted compose with a specific agent |
:ops / :queue |
Show operation queue log |
:ps / :processes |
Show running background processes |
:search <query> / :s <query> |
Search messages across all accounts |
vimail tokyonight catppuccin kanagawa gruvbox nord matrix system
vimail can use any CLI-based AI tool to help draft, rewrite, or reply to emails. Type :ai in the compose editor and the current body is sent to the AI agent — the response replaces the editor content.
- Open compose (
c), reply (r), or a draft (Enter) - Type a prompt in the body (e.g. "write a polite decline to this meeting")
- Press
Escto enter normal mode - Type
:aiand pressEnter - The hint line shows "Thinking..." while the agent runs
- The response replaces the editor body — review, edit, and send with
Ctrl+S
When replying, the quoted text (lines starting with >) is included as context, so the agent writes a reply to the original message.
Out of the box, vimail uses Claude Code CLI. If claude is in your $PATH, no configuration is needed — just use :ai.
Add an [ai] section to ~/.config/vimail/config.toml to define one or more agents:
[ai]
default = "claude"
[[ai.agents]]
name = "claude"
cmd = "claude"
args = ["--print", "-p", "{prompt}"]
[[ai.agents]]
name = "ollama"
cmd = "ollama"
args = ["run", "llama3.2", "{prompt}"]
[[ai.agents]]
name = "gemini"
cmd = "gemini"
args = ["-p", "{prompt}"]
[[ai.agents]]
name = "gpt"
cmd = "sgpt"
args = ["--no-md", "{prompt}"]
[[ai.agents]]
name = "local"
cmd = "llm"
args = ["-m", "mistral", "{prompt}"]Each agent needs:
| Field | Description |
|---|---|
name |
Identifier used with :ai <name> |
cmd |
Binary name or path (must be in $PATH) |
args |
Arguments passed to the binary. {prompt} is replaced with the full prompt |
The {prompt} placeholder is replaced with the system prompt (which includes To, Subject, and compose context) plus the editor body.
| Command | What happens |
|---|---|
:ai |
Uses the default agent |
:ai ollama |
Uses the agent named "ollama" |
:ai gpt |
Uses the agent named "gpt" |
Any tool that accepts a prompt as an argument and prints the response to stdout will work:
- Claude Code CLI —
claude --print -p - Ollama —
ollama run <model> - llm —
llm -m <model> - Gemini CLI —
gemini -p - sgpt —
sgpt --no-md - aichat —
aichat -m <model> - mods —
mods
vimail writes structured JSON logs to ~/.local/share/vimail/vimail.log. Every background operation (sync, fetch, send, delete, mark-read), user action, and error is logged with full context (account, folder, UID, duration).
Logs auto-rotate at 10 MB and are deleted after 3 days.
# Tail logs in real time
tail -f ~/.local/share/vimail/vimail.log | jq .
# Filter errors
cat ~/.local/share/vimail/vimail.log | jq 'select(.level == "error")'
# Show sync operations for a specific account
cat ~/.local/share/vimail/vimail.log | jq 'select(.op == "sync" and .account == "you@gmail.com")'main.go Entry point, subcommands (setup, help)
internal/
config/ TOML config loading
auth/ OS keyring, OAuth2 device flow, setup CLI
email/ Domain types (Account, Folder, Message), Store interface
ai/ AI agent CLI wrapper (claude, ollama, etc.)
logging/ Async structured JSON logger with rotation
cache/ SQLite schema + Store implementation
worker/ IMAP worker, SMTP worker, Coordinator
mock/ Mock data for dev mode
theme/ Theme engine + 8 themes
tui/
app.go Root bubbletea model
keys/ Mode enum + keybinding maps
util/ Shared cross-component message types
layout/ Container, split pane, overlay
components/
mailbox/ Account & folder sidebar
msglist/ Message list with viewport + visual mode
preview/ Message preview with scroll + browser open
compose/ Compose overlay with Vim editor
help/ Help overlay
status/ Status bar (mode badge, info)
pkg/
vimtea/ Vim-style editor widget
go test ./...vimail is functional with real IMAP/SMTP connectivity, app-password auth, SQLite message caching, incremental sync, and an offline operation queue. Falls back to mock data when no accounts are configured.
MIT