pm-cli is a Go CLI tool for interacting with ProtonMail via Proton Bridge IMAP/SMTP. It's designed for both terminal use and AI agent integration.
pm-cli/
├── cmd/pm-cli/main.go # Entry point, Kong parser setup
├── internal/
│ ├── cli/ # Command handlers
│ │ ├── cli.go # Kong struct definitions
│ │ ├── config.go # config init/show/set
│ │ ├── help.go # JSON help generator
│ │ ├── mail.go # mail list/read/send/delete/move/flag/search
│ │ ├── mailbox.go # mailbox list/create/delete
│ │ └── version.go # version command
│ ├── config/config.go # YAML config + keyring storage
│ ├── imap/
│ │ ├── client.go # IMAP client wrapper (go-imap v2)
│ │ └── types.go # Message/Mailbox types
│ ├── output/formatter.go # JSON/text output formatting
│ └── smtp/client.go # SMTP client for sending
github.com/alecthomas/kong- CLI frameworkgithub.com/emersion/go-imap/v2- IMAP clientgithub.com/emersion/go-message- Email parsinggithub.com/zalando/go-keyring- System keyring (libsecret)gopkg.in/yaml.v3- Config parsing
go build ./cmd/pm-cli
go install ./cmd/pm-cliRequires Proton Bridge running:
systemctl --user start protonmail-bridge
pm-cli mailbox list- Add struct to
internal/cli/cli.go:
type MailNewCmd struct {
Flag string `help:"Description" short:"f"`
}- Add to parent command struct:
type MailCmd struct {
// ...
New MailNewCmd `cmd:"" help:"Description"`
}- Implement Run method in appropriate file:
func (c *MailNewCmd) Run(ctx *Context) error {
// Implementation
}- Update
internal/cli/help.gofor JSON help schema.
All IMAP operations go through internal/imap/client.go:
client, _ := imap.NewClient(cfg)
client.Connect()
defer client.Close()
// Operations...Use the formatter for consistent JSON/text output:
if ctx.Formatter.JSON {
return ctx.Formatter.PrintJSON(data)
}
fmt.Println(textOutput)- Uses STARTTLS on port 1143 (IMAP) and 1025 (SMTP)
- Self-signed certificates require
InsecureSkipVerify: true - Password is Bridge-generated, not Proton account password
- Some emails are HTML-only;
htmlToText()handles conversion
- TLS handshake error: Bridge uses STARTTLS, not implicit TLS
- Login failed: Check Bridge password (not Proton password)
- Bridge not running:
systemctl --user start protonmail-bridge - No body content: Single-part HTML emails need special parsing
Tasks are tracked in .beads/issues.jsonl using the BEADS format. Use bd list to view open items.