From Zero to ProtonMail at the CLi
I'm going to cover installing software on Nixos to be able to use the ProtonMail Bridge at the command line so that mutt may be used as an email client. I'll cover mutt and mailcap configuration here, but any other client could reasonably be used as well.
Note: protonmail-bridge requires a paid subscription to ProtonMail.
The overall process is as follows:
• install software
• configure pass
• start the bridge
• get credentials
• configure mutt
• configure mailcap
And then I'll point out some ways to take advantage of extra stuff in the mutt configuration.
Install Software
Okay, first, I'm putting T383838protonmail-bridge and T383838pass in my user's packages and configure gpg to take passwords via the curses interface so I can have a password on my gpg identity later.
│ Libsecret is needed so that protonmail-bridge can interact with pass. Without
│ it, it will suggest installing pass but not use it.
T282828
usersTff7b72.usersTff7b72.Ta5d6ffstephen Tff7b72= Tb4b4b4{
T8b949e# normal stuff…
Ta5d6ffpackages Tff7b72= Tff7b72with pkgsTb4b4b4; Tb4b4b4[
pass
libsecret
protonmail-bridge
mutt
mutt-ics
w3m
calcurse
abook
T8b949e# other packages, too…
Tb4b4b4]Tb4b4b4;
Tb4b4b4}Tb4b4b4;
programsTff7b72.gnupgTff7b72.Ta5d6ffagent Tff7b72= Tb4b4b4{
Ta5d6ffenable Tff7b72= Tff7b72trueTb4b4b4;
Ta5d6ffpinentryPackage Tff7b72= pkgsTff7b72.pinentry-cursesTb4b4b4;
Ta5d6ffenableSSHSupport Tff7b72= Tff7b72trueTb4b4b4;
Tb4b4b4}Tb4b4b4;
I plan to use mutt, so I also put some stuff in there for that. I'll use w3m to convert HTML emails to decent looking text and mutt-ics to parse calendar invitations. And I'll use calcurse for a calendar so I can use those invitations. I'll use abook as a local address book.
Next, I make those changes live:
T282828
nixos-rebuild switch
Configure Pass
First, I need an identity.
nix-shell -p gnupg
gpg --full-gen-key --pinentry-mode=loopback
# pick options like ECC or just hit enter for the defaults
# I used the pm email address
For the identity (I used email) run T383838pass init on that identity.
pass init whomever@wherever.tld
Make sure it works:
pass insert foo/bar/baz
#enter a pass
#enter same pass
pass show foo/bar/baz
If all goes well, it should spit back whatever pass was entered.
Now delete that pass
pass rm foo/bar/baz
Start the Bridge
Let's get pm bridge running.
protonmail-bridge -c
# wait a few moments for it to finish starting
login
# answer prompts
Get Local Credentials
It will need to complete the initial sync, but it's also possible to just keep going, but info may scroll off the top of the screen.
Fetch the local credentials that mutt will use against the bridge:
info
I'm going to put those credentials into another password entry so that I don't have to put username and password information in my T383838.muttrc file.
pass add pm-bridge username
# enter value from info output Username
pass add pm-bridge password
# enter value from the info output Password
Take note of the ports used, probably 1143 and 1025 for IMAP and SMTP respectively.
Configure Mutt
Given the details are fetched from pass for the local proton, the following should work out of the box.
mkdir -p .config/mutt/
Put the following into T383838.config/mutt/muttrc:
T282828
Te6edf3set Te6edf3trashTff7b72=Tff7b72+Te6edf3Trash
Tff7b72#Tff7b72 Without setting this, any *deleted* message will just be archived.
Tff7b72#Tff7b72 To immediately delete a message, go to the Trash and delete it again.
Tff7b72#Tff7b72 It only looks like stuff gets expunged from the INBOX, you can only really
Tff7b72#Tff7b72 expunge from the Trash.
Tff7b72#Tff7b72 Additionally, so delete from trash will work as expected:
Te6edf3folderTff7b72-Te6edf3hook Tb4b4b4. 'Te6edf3set Te6edf3trashTff7b72=Tff7b72+Te6edf3Trash'
Te6edf3folderTff7b72-Te6edf3hook Tff7b72=Te6edf3Trash 'Te6edf3unset Te6edf3trash'
Tff7b72#Tff7b72 general settings
Te6edf3set Te6edf3my_user Tff7b72= `Te6edf3pass Te6edf3pmTff7b72-Te6edf3bridgeTff7b72/Te6edf3username`
Te6edf3set Te6edf3my_pass Tff7b72= `Te6edf3pass Te6edf3pmTff7b72-Te6edf3bridgeTff7b72/Te6edf3password`
Te6edf3set Te6edf3from Tff7b72= Te6edf3$my_user
Te6edf3set Te6edf3pgp_default_key Tff7b72= Te6edf3$my_user # Te6edf3match Te6edf3gpg Te6edf3generated Te6edf3key Te6edf3or Te6edf3change Te6edf3it
Te6edf3unset Te6edf3use_domain
Te6edf3unset Te6edf3ssl_verify_host
Te6edf3alternative_order Te6edf3textTff7b72/Te6edf3plain Te6edf3textTff7b72/Te6edf3enriched Te6edf3textTff7b72/Te6edf3html
Te6edf3set Te6edf3send_charset Tff7b72= Ta5d6ff"Ta5d6ffus-ascii:utf-8Ta5d6ff"
Te6edf3set Te6edf3use_from Tff7b72= Te6edf3yes
Te6edf3auto_view Te6edf3textTff7b72/Te6edf3xTff7b72-Te6edf3vcard Te6edf3textTff7b72/Te6edf3html Te6edf3textTff7b72/Te6edf3enriched
Te6edf3auto_view Te6edf3textTff7b72/Te6edf3calendar Te6edf3applicationTff7b72/Te6edf3ics
Tff7b72#Tff7b72 show more headers
Te6edf3unignore Te6edf3xTff7b72-Te6edf3mailerTff7b72:
Te6edf3unignore Te6edf3localdate
Tff7b72#Tff7b72 cache file locations
Te6edf3set Te6edf3header_cache Tff7b72= Ta5d6ff"Ta5d6ff~/.config/mutt/cache/headersTa5d6ff"
Te6edf3set Te6edf3message_cachedir Tff7b72= Ta5d6ff"Ta5d6ff~/.config/mutt/cache/bodiesTa5d6ff"
Te6edf3set Te6edf3certificate_file Tff7b72= Ta5d6ff"Ta5d6ff~/.config/mutt/certificatesTa5d6ff"
Tff7b72#Tff7b72 press a to add email address to address book
Te6edf3macro Te6edf3indexTb4b4b4,Te6edf3pager Te6edf3a Ta5d6ff"Ta5d6ff<pipe-message>abook --add-email-quiet<return>Ta5d6ff" Ta5d6ff"Ta5d6ffAdd this sender to AbookTa5d6ff"
Te6edf3macro Te6edf3attach Te6edf3a Ta5d6ff"Ta5d6ff<pipe-message>calcurse -i -<return>Ta5d6ff" Ta5d6ff"Ta5d6ffAdd appointment to calendarTa5d6ff"
Tff7b72#Tff7b72 type part of an address, then type tab to search the address book and auto complete it
Te6edf3unset Te6edf3query_command
Te6edf3set Te6edf3query_commandTff7b72= Ta5d6ff"Ta5d6ffabook --mutt-query '%s'Ta5d6ff"
Te6edf3bind Te6edf3editor Tff7b72<Te6edf3TabTff7b72> Te6edf3completeTff7b72-Te6edf3query
Tff7b72#Tff7b72 smtp settings
Te6edf3set Te6edf3smtp_pass Tff7b72= Te6edf3$my_pass
Te6edf3set Te6edf3smtp_url Tff7b72= Ta5d6ff"Ta5d6ffsmtp://$my_user@127.0.0.1:1025Ta5d6ff"
Te6edf3set Te6edf3smtp_authenticators Tff7b72= Ta5d6ff"Ta5d6ffgssapi:loginTa5d6ff"
Te6edf3set Te6edf3ssl_force_tls Tff7b72= Te6edf3yes
Tff7b72#Tff7b72 imap settings
Te6edf3set Te6edf3imap_user Tff7b72= Te6edf3$my_user
Te6edf3set Te6edf3imap_pass Tff7b72= Te6edf3$my_pass
Te6edf3set Te6edf3folder Tff7b72= Ta5d6ff"Ta5d6ffimap://localhost:1143Ta5d6ff"
Te6edf3set Te6edf3spoolfile Tff7b72= Ta5d6ff"Ta5d6ffimap://localhost:1143/INBOXTa5d6ff"
Te6edf3set Te6edf3postponed Tff7b72= Ta5d6ff"Ta5d6ffimap://localhost:1143/DraftsTa5d6ff"
Te6edf3set Te6edf3mbox Tff7b72= Ta5d6ff"Ta5d6ffimap://localhost:1143/[Protonmail]/All MailTa5d6ff"
Te6edf3set Te6edf3imap_keepalive Tff7b72= T79c0ff900
Tff7b72#Tff7b72 more general stuff, but all optional things
Tff7b72#Tff7b72set sort order upon viewing a mailbox
Te6edf3folderTff7b72-Te6edf3hook Tff7b72=Te6edf3INBOX 'Te6edf3set Te6edf3sortTff7b72=Te6edf3threads'
Te6edf3folderTff7b72-Te6edf3hook Tff7b72=Te6edf3INBOX 'Te6edf3set Te6edf3sort_auxTff7b72=Te6edf3lastTff7b72-Te6edf3dateTff7b72-Te6edf3received'
Te6edf3folderTff7b72-Te6edf3hook Tff7b72=Te6edf3Sent 'Te6edf3set Te6edf3sortTff7b72=Te6edf3reverseTff7b72-Te6edf3dateTff7b72-Te6edf3sent'
Te6edf3set Te6edf3mark_oldTff7b72=Te6edf3no
Te6edf3set Te6edf3date_formatTff7b72=Ta5d6ff"Ta5d6ff%F %H:%MTa5d6ff"
Te6edf3set Te6edf3index_formatTff7b72=Ta5d6ff"Ta5d6ff%D %Z %-15.15L %sTa5d6ff"
Tff7b72#Tff7b72 these are noisy, so turn them off
Te6edf3set Te6edf3markersTff7b72=Te6edf3no
Tff7b72#Tff7b72 change as appropriate for composing email
Te6edf3set Te6edf3editorTff7b72=Te6edf3nvim
Tff7b72#Tff7b72 vim like keys to go up or down in the mail list
Te6edf3bind Te6edf3pager Te6edf3k Te6edf3previousTff7b72-Te6edf3line
Te6edf3bind Te6edf3pager Te6edf3j Te6edf3nextTff7b72-Te6edf3line
Tff7b72#Tff7b72 get mail now on G
Te6edf3bind Te6edf3index Te6edf3G Te6edf3imapTff7b72-Te6edf3fetchTff7b72-Te6edf3mail
Launch, enter the password used when the gpg was initialized, and then accept the local certificate always.
mutt
Quit out of mutt with T383838Q.
Mailcap
Almost there, just need some message handling to convert HTML to text and make it possible to view calendar invites.
Put the following in T383838~/.mailcap:
T282828
text/html; w3m -B -o display_link_number=1 -I %{charset} -T text/html ; copiousoutput
text/calendar; mutt-ics; copiousoutput
application/ics; mutt-ics; copiousoutput
Taking advantage of the config
Add the currently selected sender to the address book by hitting T383838a.
Add the currently selected attachment to the calendar by hitting T383838a. This is intended to be run against ical attachments.
When reading a message, T383838j and T383838k will move to the previous or next line of the message instead of going to the previous or next email.
When composing a message, with T383838m, I can type a few letters and then hit Tab to complete with addresses. I can actually just hit Tab and every known address will pop in, but I find that less useful.
If the current message contains an ics file, it will simply be displayed. If the current message is html, it will get converted to txt by way of w3m and display the message inline.
I don't have any fancy key bindings yet for ingesting calendar entries into calcurse.
Tags: nixos, protonmail, cli
Tags
Navigation
Backlinks
created: 2025-01-24
(re)generated: 2026-07-17