postline

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 19, 2026 License: MIT

README

██████╗  ██████╗ ███████╗████████╗██╗     ██╗███╗   ██╗███████╗
██╔══██╗██╔═══██╗██╔════╝╚══██╔══╝██║     ██║████╗  ██║██╔════╝
██████╔╝██║   ██║███████╗   ██║   ██║     ██║██╔██╗ ██║█████╗  
██╔═══╝ ██║   ██║╚════██║   ██║   ██║     ██║██║╚██╗██║██╔══╝  
██║     ╚██████╔╝███████║   ██║   ███████╗██║██║ ╚████║███████╗
╚═╝      ╚═════╝ ╚══════╝   ╚═╝   ╚══════╝╚═╝╚═╝  ╚═══╝╚══════╝

A mail client that lives in your terminal. Full 24-bit color, clickable buttons, and a layout that adapts from a phone-sized SSH session to an ultrawide monitor.

Gmail today, other services next — everything above the network sits behind a provider interface, so adding a service does not touch the interface.

Install

curl -fsSL https://raw.githubusercontent.com/Byte-Developments/postline/main/install.sh | sh

One static binary, no runtime to install. Works on macOS and every Linux distribution; Windows builds are published as .zip archives on the releases page.

With Go already installed:

go install github.com/Byte-Developments/postline/cmd/postline@latest

Look around first

postline --demo

Demo mode runs the full interface against sample mail. No account, no credentials, nothing stored.

Connecting your Gmail account

Run postline and sign in. It opens your browser for consent, catches the redirect on a localhost port, and stores the tokens in your OS keychain. Every launch after that connects silently.

Google will show a "Google hasn't verified this app" screen the first time. Click Advanced, then Go to Postline (unsafe). Reading mail requires what Google calls a restricted scope, and clearing that warning requires a review process this project has not completed. Postline runs entirely on your machine and has no server to send your mail to, which you can confirm from the source.

Using your own Google Cloud project

Google caps unverified apps at 100 total users. Past that, or if you would rather not authorize someone else's OAuth client, bring your own:

postline --setup

The wizard walks through it, and it only happens once:

  1. Create a Google Cloud project and enable the Gmail API for it.
  2. Under Google Auth Platform, register the app with audience External.
  3. Set the publishing status to In Production.
  4. Clients → Create Client → application type Desktop app.
  5. Paste the client ID and secret into the wizard.

Don't skip step 3. Google expires refresh tokens after seven days for any app left in Testing status, which would make you re-authorize every week. Publishing removes that limit.

A client you configure this way always takes precedence over the built-in one. POSTLINE_CLIENT_ID and POSTLINE_CLIENT_SECRET do the same thing without storing anything, which is handy for scripted installs.

To disconnect and erase everything stored — the tokens in your keychain and the locally cached mail:

postline --logout

Keys

j k / ↑ ↓ move
enter open
esc back
tab next pane
/ search
c compose
r / R / f reply / reply all / forward
ctrl+s send
e s u d archive, star, mark unread, trash
w save attachments
n load more
ctrl+r refresh
? help
q quit

The mouse works too. Labels, conversation rows, and every button are clickable, with hover states and scroll wheel support.

New mail arrives on its own: the mailbox re-fetches every couple of minutes, skipping the poll while you are composing or reading search results, and keeping the cursor on whatever conversation it was already on. ctrl+r forces a refresh. Attachments save to ~/Downloads, or wherever POSTLINE_DOWNLOAD_DIR points.

Security

  • Your mail never leaves your machine. There is no Postline server. The binary talks to Google directly and stores everything locally.
  • Bring your own OAuth client with postline --setup if you would rather not use the shared one. No credentials are committed to this repository; release builds inject them at link time.
  • Keychain storage. Tokens go to the macOS Keychain, Linux Secret Service, or Windows Credential Manager. On headless machines with no keychain, set POSTLINE_PASSPHRASE and credentials are stored in an AES-256-GCM file with a scrypt-derived key instead.
  • PKCE and state validation on the OAuth exchange, with a loopback-only redirect on a random port.
  • Remote images are never fetched. HTML mail is converted to text locally, which structurally defeats tracking pixels.
  • Narrow scopes. gmail.modify and gmail.send only. Deleting moves a conversation to Trash; Postline never requests the scope that would permit permanent deletion.
  • No telemetry. The only hosts contacted are Google's OAuth and API endpoints.

Development

make demo    # run against sample mail
make test    # run the suite
make check   # vet, gofmt, and test
make cross   # build every release platform

Requires Go 1.24 or newer. The build is CGO-free by design: it is what lets a single machine produce binaries for every platform, and what makes the result dependency-free at runtime.

Layout

cmd/postline           entrypoint
internal/ui            Bubble Tea interface: views, components, theme
internal/cache         local SQLite cache
internal/auth          OAuth2 loopback flow and credential storage
internal/mail          provider-agnostic types and the Provider interface
internal/mail/gmail    Gmail implementation
internal/mail/fake     in-memory provider for tests and demo mode
web                    postline.dev, a Next.js site

The site embeds a real rendered frame rather than a screenshot. To refresh it after an interface change, dump a frame from the demo provider into web/components/interface-frame.ts.

The design document lives in docs/superpowers/specs.

License

MIT

Directories

Path Synopsis
cmd
postline command
Command postline is a terminal mail client.
Command postline is a terminal mail client.
internal
auth
Package auth handles OAuth2 credentials and their storage.
Package auth handles OAuth2 credentials and their storage.
cache
Package cache stores fetched mail locally so Postline can render a mailbox before the network responds.
Package cache stores fetched mail locally so Postline can render a mailbox before the network responds.
mail
Package mail defines provider-agnostic email types.
Package mail defines provider-agnostic email types.
mail/fake
Package fake provides an in-memory mail.Provider for tests and offline development, so UI behavior can be exercised without network access.
Package fake provides an in-memory mail.Provider for tests and offline development, so UI behavior can be exercised without network access.
mail/gmail
Package gmail implements mail.Provider against the Gmail API.
Package gmail implements mail.Provider against the Gmail API.
ui
Package ui implements Postline's terminal interface as a Bubble Tea program.
Package ui implements Postline's terminal interface as a Bubble Tea program.
ui/components
Package components holds reusable, self-contained UI widgets.
Package components holds reusable, self-contained UI widgets.
ui/layout
Package layout turns terminal dimensions into pane geometry, so views can ask what to draw rather than each recomputing breakpoints.
Package layout turns terminal dimensions into pane geometry, so views can ask what to draw rather than each recomputing breakpoints.
ui/theme
Package theme holds Postline's color palette and shared Lip Gloss styles.
Package theme holds Postline's color palette and shared Lip Gloss styles.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL