Skip to content

semos-labs/epist

Repository files navigation

Epist

Epist

Terminal email client with vim-style keybindings

Latest Release Downloads Bun MIT License Built with Glyph

Why EpistQuick StartKeybindingsCommandsConfigurationComparison


Epist is a keyboard-driven email client for the terminal, built with Glyph. Gmail OAuth + IMAP/SMTP, two-column layout, threaded conversations — manage your inbox without leaving the terminal.

Epist in action
Inbox view — email list on the left, full message on the right


Why Epist

Built for people who live in the terminal and want email to feel like vim, not like a web browser.

  • Vim keybindingsj/k, gg/G, h/l, / to search, : for commands. Feels like home.
  • Two-column layout — email list on the left, full view on the right. No pane juggling.
  • Gmail + IMAP/SMTP — Gmail OAuth with PKCE and generic IMAP/SMTP. Use any provider, mix both.
  • Secure credentialspassword_command integration with Keychain, pass, 1Password CLI, Bitwarden, env vars.
  • Threads & labels — conversation threading with [/], Gmail labels with colored dots, collapsible categories.
  • Two-step search — instant local filtering + remote search with debouncing.
  • Compose & reply — full compose, reply, reply-all, forward, and quick inline reply with contact autocomplete.
  • Attachments & calendar — view/save/open attachments, parse .ics invites with RSVP support.
  • Bulk actions & undo — select multiple threads with x, act on many, undo with z.
  • Command palette — fuzzy-matched command bar (:) and context-aware help (?).
  • Local-first — SQLite cache, instant startup, your data stays yours.
  • Themeable — customize colors via TOML configuration.

Full comparison with other terminal email clients →


Quick Start

Homebrew (macOS / Linux)

brew tap semos-labs/tap brew install epist

Build from Source

git clone https://github.com/semos-labs/epist.git cd epist && bun install bun dev # development bun start # production

Setup

Epist supports Gmail (OAuth) and IMAP/SMTP (any email provider). You can use both simultaneously.

IMAP/SMTP (Any Provider)

Add your account to ~/.config/epist/config.toml:

[[accounts]] name = "Work" email = "me@work.com" provider = "imap" [accounts.imap] host = "imap.work.com" port = 993 security = "tls" username = "me@work.com" password_command = "security find-generic-password -a me@work.com -s epist -w" [accounts.smtp] host = "smtp.work.com" port = 587 security = "starttls" username = "me@work.com" password_command = "security find-generic-password -a me@work.com -s epist -w"

Password options:

Method Example
macOS Keychain password_command = "security find-generic-password -a me@work.com -s epist -w"
pass (GPG) password_command = "pass show email/work"
1Password CLI password_command = "op read op://Personal/WorkEmail/password"
Bitwarden CLI password_command = "bw get password work-email"
Environment var password_command = "echo $WORK_EMAIL_PASSWORD"
Plain text password = "hunter2" (not recommended)

You can add multiple [[accounts]] blocks for multiple IMAP/SMTP accounts.

Gmail (OAuth)

  1. Go to Google Cloud Console → create a project
  2. Enable Gmail API, Google Calendar API, and People API
  3. Go to "APIs & Services" → "Credentials" → "Create Credentials" → "OAuth client ID"
  4. Configure OAuth consent screen:
    • User Type: External (or Internal for Workspace)
    • Add your email as a test user
    • Scopes: gmail.modify, gmail.send, calendar.events, calendar.readonly, contacts.readonly, userinfo.email, userinfo.profile
  5. Create OAuth client ID — Application type: Desktop app
  6. Copy the Client ID and Client Secret

Add credentials to ~/.config/epist/config.toml:

[google] clientId = "your-client-id.apps.googleusercontent.com" clientSecret = "your-client-secret"

Or use environment variables:

export EPIST_GOOGLE_CLIENT_ID="your-client-id.apps.googleusercontent.com" export EPIST_GOOGLE_CLIENT_SECRET="your-client-secret"

Then connect:

:login 

Follow the OAuth flow in your browser. Epist supports multiple Google accounts — IMAP accounts are loaded automatically from config.toml.


Keybindings

Email List

Key Action
j / Next email
k / Previous email
gg First email
G Last email
Enter / Space Open email
l / View email
Tab / ` Switch to view pane
s Toggle star
e Archive
D Delete
u Toggle read/unread
r Reply
R Reply all
f Forward
c Compose new
m Move to folder
x Toggle thread selection
A Select all threads
z Undo last action
/ Search emails
: Open command bar
? Show help

Email View

Key Action
j / Scroll down
k / Scroll up
Ctrl+d Page down
Ctrl+u Page up
gg Scroll to top
G Scroll to bottom
h / / Esc Back to list
] Next message in thread
[ Previous message in thread
Tab Next link
Shift+Tab Previous link
Enter Open link
Q Quick inline reply
i Toggle headers
I Toggle image navigation
a Toggle attachments
s Toggle star
e Archive
D Delete
r Reply
R Reply all
f Forward
m Move to folder
z Undo

Calendar Invite RSVP

Key Action
y Accept invite
n Decline invite
t Maybe / Tentative

Attachment Navigation

Key Action
j / k Navigate attachments
Enter / o Open attachment
s Save attachment
S Save all attachments

Compose / Reply

Key Action
Ctrl+s Send email
Ctrl+f Toggle fullscreen
Ctrl+b Toggle Cc/Bcc fields
Ctrl+a Attach file
Ctrl+g Manage attachments
Esc Cancel

Inline Reply

Key Action
Ctrl+s Send reply
Ctrl+f Expand to full reply
Esc Cancel

Folders & Labels

Key Action
Ctrl+f Toggle folder sidebar
j / k Navigate folders
Space / Toggle categories section
Collapse categories
Esc Close sidebar

General

Key Action
q Quit
Ctrl+c Quit
Ctrl+f Toggle folder sidebar
: Open command palette
/ Search emails
? Show help (context-aware)

Commands

Open the command palette with : and type a command:

Command Action
archive Archive current email
delete Delete current email
star Toggle star
unread Toggle read/unread
move Move to folder
undo Undo last action
compose Compose new email
reply Reply to current email
reply-all Reply all
forward Forward current email
search Search emails
login Add Google account (OAuth)
logout Remove all accounts
profile Manage connected accounts (Gmail + IMAP)
sync Force sync with server
reset-sync Clear cache & full resync
help Show keybindings
quit Exit application

Configuration

Create or edit ~/.config/epist/config.toml:

[general] downloads_path = "~/Downloads" auto_mark_read = true auto_save_interval = 5 # seconds undo_timeout = 5 # seconds [signature] enabled = true text = """ -- Sent from Epist """ # Colors: black, red, green, yellow, blue, magenta, cyan, white, blackBright, etc. [theme] accent_color = "cyan" header_bg = "white" selected_bg = "blackBright" starred_color = "yellow" unread_style = "bold" # bold, color, or both [google] clientId = "" clientSecret = "" [keybinds] # Override defaults: action = "key" # Gmail account (uses OAuth — run :login to authenticate) [[accounts]] name = "Personal" email = "me@example.com" provider = "gmail" is_default = true # IMAP/SMTP account (any email provider) [[accounts]] name = "Work" email = "me@work.com" provider = "imap" signature = "--\nSent from my work account" [accounts.imap] host = "imap.work.com" port = 993 security = "tls" # "tls" (993), "starttls" (143), or "none" username = "me@work.com" password_command = "pass show email/work" [accounts.smtp] host = "smtp.work.com" port = 587 security = "starttls" # "tls" (465), "starttls" (587), or "none" username = "me@work.com" password_command = "pass show email/work"

Data Storage

Epist follows the XDG Base Directory Specification:

Configuration (~/.config/epist/): config.toml — accounts, credentials, theme, keybinds.

Data (~/.local/share/epist/):

File Description
epist.db SQLite database (emails, labels, sync state)
accounts.json OAuth tokens and account info
account-settings.json Custom account display names
drafts/ Saved email drafts
logs/ Application logs

Override with XDG_CONFIG_HOME and XDG_DATA_HOME environment variables.


Comparison

Side-by-side with other terminal email clients:

Feature Epist NeoMutt aerc Himalaya Alpine meli
Protocol Gmail API + IMAP/SMTP IMAP/POP3/SMTP IMAP/SMTP/Notmuch IMAP/SMTP IMAP/POP3/SMTP IMAP/Notmuch/Maildir
Gmail OAuth (built-in) ❌¹ ⚠️² ⚠️²
IMAP/SMTP support ✅ Any provider
Setup complexity brew install + :login Extensive .muttrc config Moderate config files Moderate config Menu-driven setup TOML config
Secure credentials password_command
Vim keybindings ✅ Out of the box ✅ Customizable ✅ Inspired ❌ CLI only ❌ Menu-driven ⚠️ Partial
Two-column layout ✅ List + preview ❌ Single pane ❌ Single pane ❌ CLI only ❌ Single pane
Thread view ✅ Navigate with [/] ⚠️ Basic
Multi-account ✅ Mix Gmail + IMAP ✅ Complex config
Calendar invites (ICS) ✅ Parse + RSVP ⚠️ View only
Contact autocomplete ✅ From history ✅ With aliases
Local cache / offline ✅ SQLite ⚠️ Header cache ⚠️ Maildir
Search ✅ Local + remote ✅ With notmuch ✅ Basic ✅ With notmuch
Gmail labels & categories ✅ Colored dots ⚠️ Via IMAP folders ⚠️ Via IMAP folders ⚠️ Via IMAP folders ⚠️ Via IMAP folders ⚠️ Via IMAP folders
Undo actions
Command palette ✅ Fuzzy matching
Inline quick reply
Context-aware help ✅ Press ? anywhere
Bulk actions ✅ Select + act ✅ Tag patterns
Themeable ✅ TOML config .muttrc stylesets ✅ Limited ✅ Themes
Written in TypeScript (Bun) C Go Rust C Rust

¹ Requires external helper scripts (e.g. oauth2.py) or app-specific passwords
² Supports OAuth via external credential commands, requires manual setup

TL;DR — Epist is built for people who want a modern, keyboard-driven terminal email experience with zero friction. Gmail users get one-command OAuth setup. IMAP/SMTP users get secure password_command integration with any secret manager. Mix both in a single client.


Tech Stack

Component Technology
Runtime Bun
UI Framework Glyph — React renderer for terminal UIs
State Management Jotai
Database SQLite via Drizzle ORM
IMAP ImapFlow
SMTP Nodemailer
MIME Parsing Mailparser
Date/Time Luxon
NLP Dates chrono-node
HTML Rendering Cheerio + Turndown + Marked
Validation Zod

Roadmap

✅ Completed

  • Gmail sync via OAuth with PKCE
  • IMAP/SMTP support (any email provider)
  • Secure credentials via password_command
  • Multi-account support (mix Gmail + IMAP)
  • Two-column layout (list + view)
  • Thread view with message navigation
  • Compose, reply, reply-all, forward
  • Quick inline reply
  • Contact autocomplete from email history
  • Dynamic Gmail labels & folders with colored dots
  • IMAP folder auto-discovery (special-use flags + name heuristics)
  • Collapsible Gmail categories
  • Two-step search (local + remote)
  • Attachment view, save, and open
  • Calendar invite parsing (inline + .ics attachments)
  • Calendar invite RSVP
  • Bulk selection & actions
  • Undo support
  • Move to folder picker
  • Star, archive, delete, mark read/unread
  • Command palette with fuzzy matching
  • Context-aware help dialog
  • Local SQLite cache with instant startup
  • Background sync (10s interval)
  • Image navigation mode
  • Link navigation with Tab
  • Configurable theme & keybinds
  • XDG Base Directory support
  • Draft auto-save
  • Homebrew distribution

📋 Planned

  • Downloadable binaries
  • Offline mode improvements
  • IMAP IDLE push notifications
  • Email templates
  • PGP/GPG encryption

License

MIT © 2025


Built with Glyph • React • a lot of ANSI escape codes

Packages

 
 
 

Contributors