proton-cli Roman-16
winget install --id=Roman-16.ProtonCLI -e Unofficial, end-to-end encrypted CLI for Proton Mail, Drive, Calendar, Pass and Contacts.
winget install --id=Roman-16.ProtonCLI -e Unofficial, end-to-end encrypted CLI for Proton Mail, Drive, Calendar, Pass and Contacts.
Read your mail, move files in and out of Drive, manage calendars, passwords, and contacts, all without opening a browser. proton logs in the way the Proton apps do and does the encryption on your machine, so your keys stay yours.
--dry-run on everything that changes state, showing the rows it would touch.| Method | Command |
|---|---|
| Linux, macOS | curl -fsSL https://raw.githubusercontent.com/roman-16/proton-cli/main/scripts/install.sh | sh |
| Windows | irm https://raw.githubusercontent.com/roman-16/proton-cli/main/scripts/install.ps1 | iex |
| Homebrew | brew install --cask roman-16/tap/proton-cli |
| winget | winget install Roman-16.ProtonCLI |
| Arch (AUR) | yay -S proton-cli-bin |
| Nix | pkgs.proton-cli |
| npm | npm install -g @roman-16/proton-cli |
Debian, Ubuntu, Linux Mint - the APT repository, so it updates with the rest of your system:
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://roman-16.github.io/proton-cli/gpg.key | sudo tee /etc/apt/keyrings/proton-cli.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/proton-cli.asc] https://roman-16.github.io/proton-cli stable main" | sudo tee /etc/apt/sources.list.d/proton-cli.list
sudo apt update && sudo apt install proton-cli
There are also .rpm and .apk packages, plain binaries with checksums, and go install. See Installation.
The command is proton, and proton-cli works too - every install puts both names on your PATH.
Already installed? proton update, and proton changelog for what that brings. An install no package manager owns says so itself, once a day.
$ proton account login
Email: you@proton.me
Password:
Two-factor code: 123456
✓ Signed in as you@proton.me.
That's the whole setup. Signing in saves the session and unlocks your keys, so your password is needed once on this machine and not again. Every command documents itself with --help:
proton mail messages list
proton mail messages send --help
Scripting it? proton account login --user you@proton.me --password-file /run/secrets/proton needs no terminal. Juggling a personal and a work account? proton account login --profile work. More in Getting started.
Every command reads the same way - proton - and anywhere one wants an ID, a subject, name, or URL works too. Lists shorten IDs to 8 characters you can paste straight back. See The language.
proton mail messages list --unread
proton mail messages search --from billing@example.com --after 2026-01-01
proton mail messages get "Invoice #2291"
proton mail messages send --to alice@proton.me --subject Report --body "See attached." --attach ./report.pdf
proton mail messages reply "Invoice #2291" --body "Thanks, paid today."
proton mail messages forward "Invoice #2291" --to alice@proton.me
proton mail drafts create --to team@example.com --subject Standup --body "Notes to follow."
proton mail messages label "Invoice #2291" --label Accounting
proton mail messages export --folder archive --older-than 1y --output-dir ./backup
proton mail messages trash --unread --older-than 30d
Threads, attachments, filters, and auto-reply. → Mail
proton drive items list /Documents
proton drive items upload --recursive ./project /Backup
proton drive items upload --if-exists replace ./report.pdf /Documents
proton drive items download /Documents/report.pdf --output-dir .
proton drive items move /Documents/report.pdf --into /Archive
proton drive share link /Documents/report.pdf --expires 7d --password hunter2
proton drive items trash --pattern "*.tmp" --scope /Build --recursive
Revisions, sharing with people, and photo albums. → Drive
proton calendar events list --start 2026-04-15 --end 2026-04-30
proton calendar events create --title Dentist --start 2026-04-16T14:00 --duration 1h
proton calendar events create --title Standup --start 2026-04-16T09:00 --duration 15m --rrule "FREQ=WEEKLY;COUNT=10" --remind 15m
proton calendar events update 4f2a1b9c@2026-04-22T09:00 --start 2026-04-22T10:30
proton calendar events delete 4f2a1b9c@2026-05-04T09:00 --future
proton calendar events respond "Team sync" --status accept
Recurring events occurrence by occurrence, your own calendars, all-day events, and attendees. → Calendar
proton pass items list --vault Work
proton pass items get github.com
proton pass items create --name GitHub --username roman --password "$(openssl rand -base64 24)" --url github.com
proton pass aliases create --prefix shop --mailbox me@proton.me
Notes, cards, SSH keys, and identities. → Pass
proton contacts list
proton contacts create --name "Jane Roe" --email jane@example.com
proton contacts keys pin jane --key jane-pubkey.asc
proton contacts groups add GROUP_ID jane
Multiple addresses, organizations, and birthdays. → Contacts
proton account get
proton account sessions list
proton account settings set locale de_AT
proton account logout --revoke
Profiles and per-app settings. → Account
proton api reaches any endpoint the commands don't.
# creating something prints its new ID to stdout
ID=$(proton mail settings labels create --name Work --color purple)
# every list is an envelope keyed by its plural name, always with a count
proton mail messages list --unread --output json | jq -r '.messages[].subject'
proton drive items list /Backup --output json | jq '[.items[].size] | add'
# stream through, no temporary files
pg_dump mydb | gzip | proton drive items upload - /Backups/db.sql.gz
# archive a folder to disk as ordinary .eml files
proton mail messages export --folder archive --all --output-dir ./mail-backup
# check what a bulk change would touch before it happens
proton mail messages trash --from newsletter@example.com --older-than 90d --dry-run
Data goes to stdout and progress to stderr, so redirects stay clean. Exit codes tell user error, auth failure, not-found, ambiguity, and network trouble apart, so scripts can react to each. → Scripting
Anything that removes permanently, or that removes what a filter picked out rather than what you named, shows the rows and asks first. Off a terminal it refuses instead, so an unattended run fails safe until you add --yes. → When it asks first
Your password never reaches Proton: login is SRP, and the key password it derives stays local and unlocks your PGP keys in memory. Mail, files, events, contacts, and Pass items are decrypted after they arrive and encrypted before they leave, with the same key hierarchy the web clients use. Signatures on incoming mail are checked and reported.
The saved session keeps your key password encrypted with a key held server-side, so revoking the session from any Proton app makes a leaked copy of the file useless. proton is unaudited, and the whole storage model is written down in Security. The mechanics are in How it works.
Everything lives in docs/:
| Page | What's in it |
|---|---|
| Installation | Every platform, updating, the update notice, uninstalling |
| Configuration | Credentials, profiles, environment variables |
| Getting started | Signing in, completion, profiles |
| The language | The grammar: apps, collections, verbs, filters |
| Output | The four response kinds, JSON, colour, exit codes |
| References | Names, short IDs, compound IDs |
| Command reference | Everything · Mail · Drive · Calendar · Pass · Contacts · Account · API |
| Scripting | Pipelines, jq, cron and systemd |
| How it works | Login, keys, what's encrypted with what |
| Limitations | Platform constraints and gaps |
CHANGELOG.md records what each version changed, and proton changelog prints it.
--color purple) or hex (--color "#8080FF"); an invalid --color prints the whole palette, and lists show the swatch and the name rather than a hex code. Everything proton colors on its own account it asks for by name, so the shades come from your terminal theme rather than from here.move --into and label --label are separate verbs.Bug reports, ideas, and pull requests are all welcome. CONTRIBUTING.md covers the setup, and SECURITY.md has the private channel for security issues.
proton is an independent, community-built project. It is not endorsed by, affiliated with, or supported by Proton AG. Proton is a trademark of Proton AG. Use it at your own risk, and mind Proton's terms of service.