Read, send, search and organize Proton Mail from your terminal. Bodies are decrypted on your machine, and outgoing mail is encrypted and signed with your address key.
This page is what people actually do. For every command and flag, see the reference: messages, conversations, drafts, settings.
proton mail messages list # the inbox
proton mail messages list --unread
proton mail messages list --folder archive
proton mail messages get "Invoice #2291" # headers, body, attachment list
proton mail messages get REF --body-only > body.txtFolders are inbox, sent, drafts, trash, spam, archive, starred, scheduled, snoozed, all, or any label. Proton's inbox tabs are folders too: social, promotions, updates, newsletters, transactions.
get shows the plain-text body by default. --render html gives you the original markup, --render raw the untouched body, and --strip-quotes drops quoted reply blocks.
A Signature: line reports the verdict of the signature check against the sender's key.
A message Proton flagged carries two more lines:
$ proton mail messages get 5bH2mQxK
Subject: Your account will be suspended
From: PayPal <security@paypa1-secure.com>
To: me@proton.me
Date: 2026-04-15 14:32
Signature: unsigned
DMARC: failed
Flagged: phishing
ID: 5bH2mQxKFlagged: reads phishing, suspicious, or both. DMARC: failed means the sender's domain did not vouch for the message, so the address it claims to come from may not be the address it came from.
list marks the same messages with ✗ in the FLAGS column. In --output json each verdict is a field of its own: phishing, suspicious and dmarc_failed, present only when true.
proton mail messages mark legitimate REF # Proton was wrong about this one
proton mail messages mark phishing REF # report it, and file it as spammark legitimate settles the Flagged: verdict on that message alone, and the DMARC: line stays. To let a sender through from now on, see Who reaches the inbox.
mark phishing sends the message to Proton decrypted, body included, for their anti-abuse team to read. Nothing withdraws a report. To keep a sender out without reporting anything, use proton mail settings senders block.
Searching is list with a filter. list looks in the inbox; --folder all searches everything.
proton mail messages list --keyword invoice --folder all
proton mail messages list --from billing@example.com --after 2026-01-01 --folder all
proton mail messages list --subject "Q1 report" --folder archive--from and --to match addresses. --keyword matches the subject, a display name and an address.
Bodies are not searched. To search what a message says, build an index on this machine: Local index. With one, --keyword covers bodies and --from covers display names.
--after and --before are the first and last whole days to include, read in your own zone, and both are included.
A change reaches list a few seconds late. To confirm one right away, get the ID the command printed.
proton mail messages send --to alice@proton.me --subject Hi --body "Hello there"
proton mail messages send --to alice@proton.me --subject Report --body "See attached." --attach ./report.pdf
proton mail messages send --to alice@proton.me --subject Hi --body "<b>Hi</b>" --html
echo "Deployed." | proton mail messages send --to me@proton.me --subject Deploy --body -send prints the new message ID on stdout, so ID=$(proton mail messages send …) works.
Your signature is applied automatically: the address's own signature, plus Proton's "Sent with Proton Mail secure email." footer when your account has it enabled. Free accounts have that footer forced on.
--no-signatureleaves both out of one message.proton mail settings set pm-signature offturns the footer off account-wide.
On an account with several addresses, --from chooses which one it leaves from, plus-aliases included:
proton mail messages send --from work@example.com --to alice@proton.me --subject Hi --body Helloproton mail messages send … --send-at 2026-05-01T09:00 # local time; confirms the resolved time
proton mail messages send … --expires 7d
proton mail messages send … --eo-password-file /run/secrets/jane --eo-password-hint "our usual"
pass show mail/jane | proton mail messages send … --eo-password-file -The password a recipient outside Proton types comes from a file or from standard input, never from a flag value. It needs at least eight characters.
Such a message expires after 28 days whatever --expires says. --eo-password-file - takes the stream for itself, so it cannot be combined with --body -.
To read one that was sent to you, see Open a password-protected message somebody sent you.
A scheduled send sits in the scheduled folder until it goes. To pull it back to Drafts, run proton mail messages unschedule REF.
proton mail messages reply "Invoice #2291" --body "Thanks, paid today."
proton mail messages reply REF --everyone --body "Looping in the team."
proton mail messages forward REF --to alice@proton.me --body "FYI"
proton mail conversations reply REF --body "Works for me." # newest message in a threadThe original is quoted below your text, the subject gains Re: or Fw: (never twice), and the thread stays a thread.
A reply leaves from the address the original arrived on. A forward carries the original's attachments without re-uploading them.
--no-quotesends your text alone.--no-attachmentsleaves them behind.--draftstops before sending and prints the new draft's ID, the same as clicking Reply and leaving the composer open.
Reply and forward take everything send takes.
A draft is a message, so messages get, move and the rest already work on one. mail drafts holds what only makes sense before it goes out.
proton mail drafts create --to alice@proton.me --subject Report --body "Draft one."
proton mail drafts update REF --body "Draft two." --attach ./report.pdf --detach old-annex.xlsx
proton mail drafts send REFupdate replaces only what you pass. --to, --cc and --bcc replace the whole list; --attach adds a file and --detach removes one.
REF resolves within Drafts only, so editing "Report" can never reach a message you already sent. Sending a draft delivers it exactly as stored.
A message lives in exactly one folder and carries any number of labels. So moving and labelling are different verbs, and passing a label to move is an error rather than a silent relabel.
proton mail messages move REF --into archive # it leaves where it was
proton mail messages label REF --label Work # it stays where it is
proton mail messages mark read REF
proton mail messages star REF
proton mail messages trash REFEvery one of those takes filters instead of references, and acts on everything that matches:
proton mail messages trash --unread --older-than 30d
proton mail messages move --into archive --from newsletter@example.com --older-than 7d
proton mail messages delete --folder spam --allAdd --dry-run to see the list first. --limit caps how many a verb touches and defaults to 150. See Filters and bulk changes.
empty is not delete --all. A filtered delete shows what it will touch. empty clears the folder whole, takes no filter, and always asks.
proton mail messages empty --folder trash
proton mail messages update REF --expires 7d # delete itself later
proton mail messages update REF --expires never
proton mail messages unsubscribe REF # ask a mailing list to stopunsubscribe uses whatever the message offered: a List-Unsubscribe header, or the one-click form behind it.
Conversations are whole threads, with the same verbs as messages.
proton mail conversations get REF # every message, chronological
proton mail conversations get --summary REF # one line per message
proton mail conversations snooze REF --until 3dSnooze works on threads, not messages: a conversation leaves the inbox as a whole and returns as a whole.
--until takes a duration from now or a moment. A moment in the past is refused.
proton mail messages attachments list REF
proton mail messages attachments download REF --dest-dir ./attachments/
proton mail messages attachments download REF invoice-2291.pdf --dest-dir .
proton mail conversations attachments download REF --dest-dir ./thread/Naming an attachment downloads that one, by its own name or by its ID; naming none downloads them all.
Existing files are never overwritten silently: names collide into file (2).pdf, or pass --force. --include-inline covers embedded images too.
A message sent to an address outside Proton arrives as a link, and the password comes to you some other way. Name it by the link or by the id in it:
proton mail protected get 9fK2pQ7xNv4mB8 --eo-password-file /run/secrets/jane
proton mail protected get 'https://mail.proton.me/eo/9fK2pQ7xNv4mB8' --eo-password-file -
proton mail protected attachments list 9fK2pQ7xNv4mB8 --eo-password-file /run/secrets/jane
proton mail protected attachments download 9fK2pQ7xNv4mB8 --eo-password-file /run/secrets/jane --dest-dir .Quote the link: a shell splits nothing in an id, and everything in a URL.
The password is the one whoever sent the message gave you, not a Proton password, and it comes from a file or from standard input.
$ proton mail protected get 9fK2pQ7xNv4mB8 --eo-password-file /run/secrets/jane
Subject: Q3 numbers
From: Jane Roe <jane@proton.me>
To: me@example.com
Date: 2026-04-15 14:32
Expires: 2026-05-13 14:32
Here are the numbers we discussed.
Attachments
ID NAME SIZE
──────── ───────────── ───────
kQ81mDx4 q3-report.pdf 84.2 KBget takes the same --render, --body-only and --strip-quotes as mail messages get. The message is gone 28 days after it was sent.
An answer goes to whoever sent it and nobody else:
proton mail protected reply 9fK2pQ7xNv4mB8 --eo-password-file /run/secrets/jane --body 'Got them, thanks.'
proton mail protected reply 9fK2pQ7xNv4mB8 --eo-password-file /run/secrets/jane --body 'Signed copy attached.' --attach ./signed.pdfFive answers can go back from behind one link, and a Replies line on get counts the ones already sent.
None of this needs an account. Your own mail, login included, is untouched by it.
export writes ordinary RFC 822 files you can open in any mail client.
proton mail messages export --folder archive --older-than 1y --all --dest-dir ./backup
proton mail messages export --folder inbox --all --format mbox --dest inbox.mbox
proton mail messages export REF --dest - | formail -X ""It takes the same filters as trash and move.
--format emlwrites one file per message, named<date> <subject>.eml.--format mboxconcatenates everything into one file.--no-attachmentsskips downloads, which is much faster for a large archive.
Exported files are not encrypted. Their DKIM-Signature and ARC-* headers no longer verify either.
Going the other way, --eml reads a file back into a draft or a send:
proton mail drafts create --eml ./message.eml
proton mail messages send --eml ./message.eml --to someone-else@proton.meAny flag you also pass overrides what the file says, and no signature is appended: the file is already a finished message.
There is no way to place an old message into your archive.
proton mail messages watch
proton mail messages watch --output json | jq -c .Stays attached and prints a line the moment a message lands.
It reports what happens while it is watching, so nothing that arrived beforehand comes up. A thread coming back from snooze counts as landing.
Without --folder it covers the inbox plus every folder whose notifications are on.
Each JSON line names the thread in conversation_id, so a consumer can act on the whole thread without looking it up. See Streams and Desktop notifications.
proton mail settings folders create --name Projects
proton mail settings folders create --name Clients --parent PARENT_FOLDER_ID
proton mail settings labels create --name Important --color "#8080FF"
proton mail settings labels delete Important # by name, or by IDColours have to be one of Proton's 20 accent colours. An invalid one prints the palette and is refused before anything is sent.
Deleting a folder or label asks first. The messages it held are not deleted.
Folders carry a NOTIFY switch, which is whether mail landing there is worth telling you about. It shows in folders list, --notify sets it, and it decides what messages watch covers by default. Labels have no such switch.
Server-side filters. Describe one with --if; it is stored as Sieve and opens in the web client's filter builder afterwards.
proton mail settings filters create --name "Archive invoices" \
--if "subject contains invoice" --into Archive
proton mail settings filters create --name Receipts \
--if "sender contains billing@" --if "subject not contains draft" \
--label Receipts --mark-read
proton mail settings filters create --name Loud --match any \
--if "subject starts [ALERT]" --if "attachments contains" --starA condition reads FIELD [not] COMPARATOR VALUE:
| Part | Values |
|---|---|
| Field | subject, sender, recipient, attachments |
| Comparator | contains, is, starts, ends, matches |
is wants the whole value. matches takes * and ? as wildcards. not inverts. attachments takes no value: it asks whether there is one.
Every condition has to hold unless you pass --match any.
Actions are --into (one folder), --label (repeatable), --mark-read and --star. A filter needs at least one. Every filter skips mail Proton has already called spam.
update rewrites the rule in place and replaces the whole thing rather than adding to it. The filter keeps its place in the order and stays enabled or disabled as it was, which is what makes this different from deleting it and making a new one.
get shows the rule as it stands, in the words --if takes. To bring your own script, use --sieve -; get then shows the script itself.
A filter acts once, as mail arrives, so a rule written today does nothing about yesterday's mail:
proton mail settings filters apply # every enabled filter
proton mail settings filters reorder Receipts # run this one firstOrder decides the outcome: the first rule to file a message wins. reorder moves the filters you name to the front and leaves the rest in the order they are in.
proton mail settings autoreply set --repeat fixed \
--start 2026-07-01T09:00 --end 2026-07-14T18:00 \
--body "I'm away until the 14th."
proton mail settings autoreply disable--start and --end are written in the grammar the repeat mode dictates:
--repeat |
--start / --end |
|---|---|
fixed |
2026-07-01T09:00 - a date and time |
daily |
09:00 - a time of day, with --days mon,tue,wed |
weekly |
mon:09:00 - a weekday and time |
monthly |
1:09:00 - a day of the month and time |
permanent |
not used |
All of them take --zone, any IANA name, defaulting to your system's.
Saving a schedule turns the auto-reply on. disable keeps it for later.
Every auto-reply goes out with the subject Auto, which cannot be changed. Auto-reply is a paid feature.
Spam, block and allow are one list with a destination on each entry, so list shows all three:
proton mail settings senders list
proton mail settings senders block spammer@example.com
proton mail settings senders block @example.com # a whole domain
proton mail settings senders allow billing@example.com
proton mail settings senders remove billing@example.comA decision applies before the spam filter forms an opinion. Deciding again about the same sender replaces the earlier decision. remove lets the filter decide again.
proton mail settings forwarding create me@proton.me jane@proton.me
proton mail settings forwarding create me@proton.me jane@example.com
proton mail settings forwarding listSetting one up needs a paid Mail plan. Nothing is forwarded until the other side accepts. A Proton address accepts in its Proton client or with forwarding accept; an address outside Proton follows the link Proton emails it.
Forwarding to an address outside Proton turns off end-to-end encryption for your address. It comes back on when the last such forwarding from that address is deleted. proton mail settings addresses get me@proton.me shows whether it is on.
Setting up that kind asks for your password, and so does the delete that turns encryption back on. With no terminal, pass --password-file, which takes - for standard input. The other commands that do this are listed in Account.
proton mail settings forwarding disable jane@proton.me
proton mail settings forwarding enable jane@proton.me
proton mail settings forwarding resend jane@proton.me
proton mail settings forwarding delete jane@proton.medisable stops mail being forwarded and keeps the arrangement. resend offers it again to a forwardee who declined it, or whose material your key change left outdated. delete takes one down in either direction.
proton mail settings forwarding list
proton mail settings forwarding accept jane@proton.me
proton mail settings forwarding decline jane@proton.meA forwarding is named by the other party's address, in either direction. Only a pending forwarding sent to one of your addresses can be accepted or declined, and accepting needs no plan.
proton mail settings domains create example.com
proton mail settings domains get example.com
proton mail settings domains listAdding a domain needs a paid Mail plan, and how many you may have depends on it. Without one, every command here says so.
Changing a domain asks for your password, even when you are signed in. That is create, update and delete. With no terminal, pass --password-file, which takes - for standard input. The other commands that do this are listed in Account.
get shows every DNS entry the domain needs and re-checks your DNS each time it runs. Add the entries at your registrar, then run it again. Each check reads ok, or what Proton found instead: missing, wrong, duplicate, wrong-priority, backup, error, warning, delegated or relaxed.
$ proton mail settings domains get example.com
Domain: example.com
Status: unverified
Addresses: 0
Catch-all: (none)
Verification: missing
TXT @ protonmail-verification=7c1e4f9a2b8d6503e1f74a0cc9b2d81e5f3a6740No address can be added on the domain until Proton has seen the verification entry. Every entry has to stay in place afterwards: removing the verification entry gives the domain up.
list shows the last check rather than making a new one. Its DNS column reads ok, or names the checks that are not passing.
proton mail settings domains update example.com --catch-all work@example.com
proton mail settings domains update example.com --catch-all noneMail sent to a name your domain has not got arrives at the catch-all address instead of being refused. --catch-all takes one of your addresses on that domain, or none to refuse such mail again. One address catches at a time, so naming another moves it.
proton mail settings domains delete example.comEvery address on the domain stops sending and receiving, and the mail they hold stays. Adding the domain again needs its DNS entries verified from scratch.
proton mail settings addresses create work@example.com --display-name Work
proton mail settings addresses list
proton mail settings addresses disable work@example.com
proton mail settings addresses enable work@example.com
proton mail settings addresses delete work@example.comThe address sends and receives as soon as it exists. Its domain has to be one the account can use: a Proton domain, or a custom domain already set up. Adding, disabling and deleting an address needs a paid Mail plan.
Your first Proton address and your short-domain address stay enabled and cannot be deleted. Proton allows one address deletion a year unless the address is on a custom domain, and a deleted address cannot be used again by anyone.
get shows whether an address holds a key. One that does not can neither send nor receive; running create on it publishes the missing key.
proton mail settings addresses create alice@pm.meYour short-domain address is your username at pm.me: the local part of the address addresses list shows as original. It needs a paid Mail plan, takes the display name and signature of your default address, and once on cannot be disabled or deleted. Any other address on pm.me counts towards your address limit.
proton mail settings addresses reorder alice@pm.me
proton mail settings addresses reorder alice@pm.me work@example.com alice@proton.meThe first address is the default: addresses list shows it first, and mail leaves from it when no --from is given. Name the addresses that should come first, in order; the rest keep the order they are in. A disabled or external address, or one that cannot send or receive, cannot be the default.
proton mail settings smtp-tokens create billing@example.com --name 'Office printer'
proton mail settings smtp-tokens list
proton mail settings smtp-tokens get 'Office printer'
proton mail settings smtp-tokens delete 'Office printer'A token lets a device or a service send mail as one of your addresses. It sends from one custom domain address and nothing else, and needs a paid Mail plan. An address on a Proton domain cannot hold one.
Making and deleting a token asks for your password, even when you are signed in. With no terminal, pass --password-file, which takes - for standard input. The other commands that do this are listed in Account.
The token is shown once, when it is made. Set the device up with what create answers: the address as the SMTP username, the token as the password, and TLS turned on.
$ proton mail settings smtp-tokens create billing@example.com --name 'Office printer'
Token: 9Kd2mQxT9wLpN4vRs8kZc
Address: billing@example.com
Server: smtp.protonmail.ch
Port: 587
Name: Office printerUnder --output json the token is the token field:
TOKEN=$(proton mail settings smtp-tokens create billing@example.com --name 'Office printer' --output json | jq -r .token)get shows everything but the token, so one you have lost is deleted and made again. LAST USED in the listing is when something last sent with a token, and - where nothing ever has. Deleting a token stops the device sending.
proton mail settings get # everything, at a glance
proton mail settings list # the writable keys, grouped by page
proton mail settings set view-mode conversations
proton mail settings addresses update me@proton.me --display-name "Roman L."
proton mail settings addresses update me@proton.me --signature - < signature.html --htmlEvery key has a fixed set of values, checked before anything is sent. Values can be given by name or by number.
Signatures are stored as HTML. Plain text is escaped and its newlines become line breaks; --html passes markup through.