CLI tool
charmbracelet/pop avatar
charmbracelet/pop

charmbracelet/pop: send email from the terminal without leaving your shell

Send emails from your terminal 📬

2,910 stars74 forksGoMIT

At a glance

What is it?
Pop is a Go CLI and TUI for composing and sending mail through Resend or SMTP. It suits scripted notifications and AI-assisted drafts, and it is the wrong tool for anything needing delivery guarantees.
Who is it for?
Adopt pop if you already live in a shell and want notification mail or a quick draft-and-send loop with Resend or an SMTP relay. Skip it if you need delivery tracking, retries, templating, or a mail queue, because the README documents none of those.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 29 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 25, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What pop replaces, and who actually needs it

The gap pop fills is narrow and real: composing an email body as a file or a pipe, then handing it to a mail provider, without opening a client. The README frames the tool as "Send emails from your terminal" and shows one canonical invocation: a Markdown file on stdin, flags for sender, recipient, subject and attachment. That shape matters. Because the body arrives on stdin, pop composes with anything that writes text, and the README leans into this with three worked integrations: mods, gum and invoice.

The audience is people who already script their work. If you generate an invoice PDF with the invoice tool and want it mailed in the same shell session, pop is the last command in that pipeline. If you use Crush to draft prose, pop is the send step. The README also addresses AI agents directly, noting that pop --help is usually enough and that a builtin pop skill command exists to hand an agent a skill file. That is an unusual thing for a mail sender to document, and it tells you where the maintainers think the tool lives: inside automated, agent-driven workflows, not in a human inbox.

What pop is not is a mail client. There is no inbox view, no threading, no search. The TUI is a compose surface.

Two transports, one Markdown renderer, and how a message is assembled

The dependency list in go.mod is the clearest view of the architecture. Two sending paths are present: github.com/resendlabs/resend-go for the Resend API, and github.com/xhit/go-simple-mail/v2 for SMTP. Body rendering goes through github.com/yuin/goldmark, which is a CommonMark parser, so a Markdown body is converted to HTML before sending. The README confirms this is the default and that POP_PLAINTEXT=true or the --plaintext flag turns the conversion off.

The file layout matches that split. email.go holds message assembly, attachments.go handles file attachments, and auth.go, auth_cli.go and auth_ui.go cover the OAuth flow used to authenticate with Resend. model.go, keymap.go and style.go belong to the Bubble Tea interface, and the go.mod requires charm.land/bubbletea/v2, charm.land/bubbles/v2 and charm.land/lipgloss/v2. So the TUI and the CLI share the same sending code, and the TUI is a front end over it rather than a separate implementation.

One consequence worth stating plainly: the Markdown-to-HTML step means what you see in your editor is not literally what the recipient receives. Headers, links and emphasis get translated. The README offers --preview for exactly this reason in its Crush example, and the note there says to use it "to preview the email and make changes before sending."

Installing pop with brew, Nix, Go, or a release binary

The README lists four install routes. Package managers cover macOS and Linux, Nix has its own attribute, and there is an Arch package. Go users can install straight from the module path. The repository also ships a Dockerfile based on gcr.io/distroless/static, which copies a pop binary to /usr/local/bin/pop and sets it as the entrypoint, so a container image is possible if you build the binary first.

bash
# macOS or Linux
brew install pop

# Nix
nix-env -iA nixpkgs.pop

# Arch
yay -S charm-pop-bin

If you prefer the Go toolchain, the README gives this command, which installs the latest tagged version:

bash
go install github.com/charmbracelet/pop@latest

Before you can send anything you need credentials. The README says pop works with Resend and that the quickest start is the OAuth flow, which opens a browser. The alternative is an API key in the environment, and the README points at resend.com/api-keys for obtaining one. If you want SMTP instead, four environment variables configure it, and the README uses Gmail on port 587 as its example.

bash
export RESEND_API_KEY=$(pass RESEND_API_KEY)

# or SMTP
export POP_SMTP_HOST="smtp.gmail.com"
export POP_SMTP_PORT=587
export POP_SMTP_USERNAME="[email protected]"
export POP_SMTP_PASSWORD="babyfrogsquad"

Two more variables reduce retyping. POP_FROM pre-fills the sender address, and POP_SIGNATURE appends a signature. The README shows a Markdown signature, which will be rendered along with the rest of the body. To run the interactive interface instead of the CLI, the README's instruction is a single word: pop.

Sending your first message and previewing it before it leaves

The CLI example in the README pipes a Markdown file into pop and passes the envelope fields as flags. Note that --attach takes a filename, and the README's invoice example shows the same flag used with a generated PDF.

bash
pop < message.md \
    --from "[email protected]" \
    --to "[email protected]" \
    --subject "Hello, world!" \
    --attach invoice.pdf

The README also shows a --body flag in the invoice example, so the body can come from a flag rather than stdin. When you are drafting with an AI tool, the README's Crush recipe uses a here-string and adds --preview, which lets you inspect the rendered message and edit before sending.

bash
pop <<< "$(crush run 'Explain why CLIs are awesome')" \
    --subject "The command line is the best" \
    --preview

If your sender or recipient list is not fixed, the README pairs pop with gum: gum choose picks the from address, and gum filter reads a contacts file for the to address. That is the whole pattern. Pop takes flags and stdin; the surrounding tools decide what goes in them.

Where pop stops: no queue, no delivery feedback, no templates

The README documents sending and nothing after it. There is no mention of retries, bounce handling, delivery status, rate limits, or what pop does when the provider returns an error. For a notification email that is fine. For anything a user depends on, you are trusting the provider and whatever wrapper you wrote.

There is a second, subtler boundary. Because Markdown is converted to HTML by default, the plaintext alternative is opt-in through POP_PLAINTEXT or --plaintext. Some recipients and some filters treat HTML-only mail differently from multipart mail, and the README does not describe a multipart mode where both bodies are sent. If plaintext matters to your audience, you set the flag and give up formatting.

Configuration is environment-only apart from the OAuth flow. There is no config file documented, which means credentials live in your shell environment or your process manager. That is convenient for scripts and awkward for anyone who wants per-project sender identities without exporting variables in every context.

Finally, the README notes a Resend constraint: without a custom domain you can send from [email protected]. That is a testing convenience, not a production sender identity, and the README presents it that way.

How pop differs from calling the provider SDK or a mail library directly

The honest alternative is not another CLI. It is the Resend SDK or an SMTP library in your own code, which is what pop uses underneath. If you are writing a Go service that sends mail, importing github.com/resendlabs/resend-go or github.com/xhit/go-simple-mail/v2 gives you the same transports with full control over error handling, retries and message construction. Pop adds a command boundary, a Markdown renderer, an attachment flag and a TUI on top of that, and a command boundary is exactly what you do not want inside a long-running process.

The comparison that matters is where the message is composed. With a library, composition is code you test. With pop, composition is a shell pipeline, which is easier to write once and harder to assert on. Pop's advantage is that the pipeline is short and the tool is already installed, which is why the README's examples pair it with gum and invoice rather than showing a Go program. Choose pop when the sender is a human or an agent at a prompt. Choose the SDK when the sender is a service.

Maintenance, upgrades and what the MIT licence lets you do

The last push to the repository was on 2026-09-01, and the most recent release listed is v0.5.0 from 2026-08-20. The project is not archived. Those two facts are the whole maintenance picture available here; the README does not state a support policy or a release cadence beyond the tags themselves.

Upgrade cost looks low. The tool is a single binary distributed through brew, Nix, Arch and GitHub releases, plus a Go module path, so upgrading is a package manager command or a re-run of go install. There is no server component and no database, so there is no migration step. The Dockerfile is distroless and expects a prebuilt pop binary copied in, which means container builds are your responsibility rather than something the project publishes.

The licence is MIT. In practical terms that permits commercial use, modification and redistribution provided the copyright notice and permission notice are included. Credentials are a separate matter: the Resend API key or SMTP password you export is governed by your provider's terms, not by pop's licence. Nothing here is legal advice; read the LICENSE file in the repository if the distinction matters to your organisation.

Editorial conclusion

Adopt pop if you already live in a shell and want notification mail or a quick draft-and-send loop with Resend or an SMTP relay. Skip it if you need delivery tracking, retries, templating, or a mail queue, because the README documents none of those. Before wiring it into anything, run pop auth or export RESEND_API_KEY and send one message to yourself with --preview to confirm the body renders the way you expect.

Frequently asked questions

What is popmail?

The name popmail does not appear in this project's README. The project is charmbracelet/pop, described there as a tool to send emails from your terminal, with both a text-based user interface and a command line interface.

How do I install charmbracelet/pop?

The README lists brew install pop for macOS and Linux, nix-env -iA nixpkgs.pop for Nix, yay -S charm-pop-bin for Arch, and go install github.com/charmbracelet/pop@latest. Prebuilt binaries are also available from the releases page.

How do I configure charmbracelet/pop to send through SMTP instead of Resend?

Set POP_SMTP_HOST, POP_SMTP_PORT, POP_SMTP_USERNAME and POP_SMTP_PASSWORD in your environment. The README uses smtp.gmail.com on port 587 as its example configuration.

Can charmbracelet/pop send an email with a file attached?

Yes. The README's CLI example passes --attach invoice.pdf alongside the from, to and subject flags, and its invoice example attaches a generated PDF the same way.

How do I avoid sending a charmbracelet/pop message before checking it?

Use the --preview flag. The README's Crush example adds --preview and notes that it lets you preview the email and make changes before sending.

Official sources

  1. charmbracelet/pop on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/charmbracelet-pop.svg)](https://hysenlabs.com/projects/charmbracelet-pop)