- Title:
- mutt: the powerful mua
- Authors:
- Paolo Vincenzo Olivo
- Date:
- Topics:
- Lowtech
- Id:
- nesbk9
> "All clients suck. This one just sucks less." -me, circa 1995 <http://www.mutt.org/>
Today we discuss how to setup neomutt as a comfortable, integrated and versatile CLI MUA, while trying to keep resource requirements as low as possible, so as to ideally provide a viable solution for legacy hardware, embedded systems, headless computers, and public access shells.
It is, nevertheless, within the scope of the following the setup the idea of showing how a text-only client can still perfectly adapt to everyday computing, and keep up with modern standards. I've been using mutt only for years so far, and have become used to its many good design choices to the point I find it hard to fancy myself happily using webmail now.
In addition, I'd like to underline how competent and helpful are the people on the official mailing list and newsgroup (comp.mail.mutt). Since I subscribed to those, I've been indirectly given a good amount of interesting hints.
■ requirements
- mail/neomutt. You may also use mutt, but some features will be unsupported unless you apply local patches (e.g. the sidebar).
- mail/msmtp, as SMTP client. The are many alternatives here. A possible replacement which I've been looking into lately is DragonFly BSD's dma. See <https://github.com/corecode/dma>.
- security/gnupg2, to encrypt/decrypt and sign messages, as well as encrypt/decrypt passwords on the fly. This tutorial assumes you already configured GnuPG properly to use your secret key(s).
- databases/abook as an addressbook to store and manage aliases
- a third-party editor, if you find nvi to be too conservative.
■ preliminary tasks
1. Create directories to store mutt files
$ for d in accounts bodies cache certificates headers private themes tmp > do mkdir -p ~/.mutt/${d} > done
2. store your imap/smtp password as an encrypted hidden file
$ echo -e "your password here\n" | gpg2 --encrypt -o ~/.msmtp.gpg # enter key ID $ chmod 600 ~/.msmtp.gpg
3. generate self-signed client certificate and for mutt:
$ openssl req -x509 -newkey rsa:4096 -days 365 -keyout \ ~/.mutt/private/mutt.key -out ~/.mutt/certificates/mutt.crt
4. create a ~/.signature file with your signature, try not to make it longer than 4 lines:
----------------------------+---------------------------- vms[-at-]retrobsd.ddns.net | https://retrobsd.ddns.net
5. configure msmtp by editing a ~/.msmtprc file like below: # Set default values for all following accounts. defaults auth on tls on tls_starttls on tls_trust_file /etc/openssl/certs/ca-certificates.crt tls_cert_file ~/.mutt/certificates/mutt.crt tls_key_file ~/.mutt/private/mutt.key syslog on tls_certcheck on logfile ~/.msmtp.log # home server account homelab host mx.retrobsd.ddns.net port 587 user vms@retobsd.ddns.net from Paolo Vincenzo Olivo <vms@retrobsd.ddns.net> passwordeval "gpg2 --quiet --for-your-eyes-only --no-tty --decrypt ~/.msmtp.gpg"
account default : homelab
■ configuration files
What follows is a sample configuration, modeled after my personal one. It is purposedly commented for readers to understand what the various options stand for. Feel free to experiment with it a bit and adjust it to your needs.
--------------------------------------------------------------------- DISCLAIMER: I've put this setup together by copying, adapting, drawing ideas from and mixing, various other configurations found online and therefore do not retain any right over the files that follow. If you stumble across this post and want to be credited as author or wish for it to be removed do not hesitate to email me. ---------------------------------------------------------------------
Change working directory to ~/.mutt and touch/edit the required files, as shown below:
1. muttrc # =================== MUTT CONFIGURATION ==================== # ## S S L # force encryption set ssl_force_tls = "yes" # default to TLSSv1.3 set ssl_use_tlsv1_3 = "yes" # and STARTTLS set ssl_starttls = "yes" # e n c o d i n g # default to us-ascii (using iso-8859-1 as fallback) set send_charset = "us-ascii:utf-8:iso-8859-1" # decode RFC-2047-encoded MIME parameters set rfc2047_parameters = "yes" # decode headers/bodies before searching set thorough_search = "yes" # a p p e a r a n c e set date_format = "%y/%m/%d %I:%M%p" set index_format = "%2C %zs %?X?A& ? %D %-15.15F %s (%-4.4c)" set pager_format = "-%Z- %C/%m: %-20.20n %s%* -- (%P)" set pager_context = "3" set forward_format = "Fwd: %s" # Disables the `+` displayed at line wraps set markers = "no" # h e a d e r s ignore "Authentication-Results:" ignore "DomainKey-Sighnature:" ignore "DKIM-Signature:" hdr_order From: Resent-From: Reply-To: X-Mailer: User-Agent: Date: To: Cc: Subject: my_hdr Organization: RetroBSD Net my_hdr User-Agent: `/usr/pkg/bin/neomutt -v | head -n 1` my_hdr X-Operating-System: `uname -s`, kernel `uname -r` # d i r e c t o r i e s set header_cache = "~/.mutt/cache/headers" set message_cachedir = "~/.mutt/cache/bodies" set certificate_file = "~/.mutt/certificates" set tmpdir = "~/.mutt/tmp" # a l i a s e s set alias_file = "~/.mutt/aliases" # sort aliases alphabetically set sort_alias = alias # display real names first set reverse_alias = yes # external address book command set query_command = "abook --mutt-query '%s'" # m i s c # supress waiting for informational messages set sleep_time = "0" # lock session after 15 min set timeout = "900" # display plain text bodies whenever possible alternative_order text/plain text/enriched text/html # most recent messages displayed first set sort = "reverse-date" # external editor set editor = "/usr/pkg/bin/vim" # do not automatically jump to next message set pager_stop = "yes" # Unread mail stay unread until read set mark_old = "no" # attachments are forwarded with mail set mime_forward = "yes" # mutt won't ask "press key to continue" set wait_key = "no" # skip to compose when replying set fast_reply = "yes" # save attachments with the body set fcc_attach = "yes" # include message in forwards set forward_quote = "yes" # reply as whomever it was to set reverse_name = "yes" # include message in replies set include = "yes" # avoid lags using IMAP with some email providers set mail_check = "60" # automatically show html (mailcap uses w3m) auto_view text/html # and encrypted messages auto_view application/pgp-encrypted # notifications set new_mail_command = "notify-send -i /usr/pkg/share/icons/Adwaita/16x16/status/mail-unread.png -a "mutt" 'New Email in %f' '%n new messages, %u unread.' &" # external configuration files to read source ~/.mutt/accounts/homelab source ~/.mutt/sidebar source ~/.mutt/binds source ~/.mutt/gpg.rc source ~/.mutt/themes/my-theme-name source ~/.mutt/aliases
2. accounts/homelab # =================== ACCOUNT SETTINGS==================== # # general settings set realname = "Paolo Vincenzo Olivo" set imap_user = "vms@retrobsd.ddns.net" set imap_pass = "`gpg2 --quiet --for-your-eyes-only --no-tty --decrypt ~/.msmtp.gpg`" set folder = "imaps://mx.retrobsd.ddns.net:993/" set spoolfile = +INBOX set postponed = +Drafts set record = +Sent set trash = +Trash set sendmail = "/usr/pkg/bin/msmtp -a homelab -t" set from = "Paolo Vincenzo Olivo <vms@retrobsd.ddns.net>" set signature = "~/.signature" set mail_check = 90 # generate 'From:' headers set use_from = yes # fetch the set of subscribed folders from server set imap_check_subscribed = "yes" # only display subscribed folders set imap_list_subscribed = "yes" # make use of the IMAP IDLE extension set imap_idle = "yes" # poll open IMAP conections every 3 mins set imap_keepalive = 180
3. gpg.rc # =================== PGP SETTINGS ==================== # # g e n e r a l set crypt_autosign = "yes" set pgp_sign_as = "vms@retrobsd.ddns.net" set pgp_sign_as = "my PGP key ID" # no mail encryption by default unset crypt_autoencrypt # but encrypt replies to encrypted mails set crypt_replyencrypt = "yes" # always attempt to verify signatures set pgp_verify_sig = "yes" # encode signed messages as quoted-printable set pgp_strict_enc = "yes" # let gpg-agent handle passphrase prompts set pgp_use_gpg_agent = "yes" # cached passphrase shall expire after 1h time set pgp_timeout = 3600 # m a c r o s set pgp_decode_command = "gpg2 %?p?--passphrase-fd 0 --pinentry-mode=loopback? --no-verbose --batch --output - %f" set pgp_verify_command = "gpg2 --no-verbose --batch --output - --verify %s %f" set pgp_decrypt_command = "gpg2 %?p?--passphrase-fd 0 --pinentry-mode=loopback? --no-verbose --batch --output - %f"rsa set pgp_sign_command = "gpg2 --no-verbose --batch --output - %?p?--passphrase-fd 0 --pinentry-mode=loopback? --armor --detach-sign --textmode %?a?-u %a? %f" set pgp_clearsign_command = "gpg2 --no-verbose --batch --output - %?p?--passphrase-fd 0 --pinentry-mode=loopback? --armor --textmode --clearsign %?a?-u %a? %f" set pgp_encrypt_only_command = "/usr/pkg/libexec/neomutt/pgpewrap gpg2 --batch --quiet --no-verbose --output - --encrypt --textmode --armor --always-trust -- -r %r -- %f" set pgp_encrypt_sign_command = "/usr/pkg/libexec/neomutt/pgpewrap gpg2 %?p?--passphrase-fd 0 --pinentry-mode=loopback? --batch --quiet --no-verbose --textmode --output - --encrypt --sign %?a?-u %a? --armor --always-trust -- -r %r -- %f" set pgp_import_command = "gpg2 --no-verbose --import -v %f" set pgp_export_command = "gpg2 --no-verbose --export --armor %r" set pgp_verify_key_command = "gpg2 --no-verbose --batch --fingerprint --check-sigs %r" set pgp_list_pubring_command = "gpg2 --no-verbose --batch --quiet --with-colons --with-fingerprint --list-keys %r" set pgp_list_secring_command = "gpg2 --no-verbose --batch --with-colons --with-fingerprint --list-secret-keys %r"
4. binds # =================== SHORTCUTS ==================== # # Non-standard, more vim-like key mappings # # Free keys bind index h noop bind index,pager d noop #used for dX bind index,pager i noop #used for goto iXY and i[1-9] in account muttrc (XY = 2 mailbox letters) bind index,pager M noop #used for CXY, "move" to XY in account muttrc bind index,pager C noop #used for CXY, "copy" to XY in account muttrc bind pager,attach,browser,index g noop # i n d e x bind index gg first-entry bind index G last-entry bind index p recall-message bind index R group-reply bind index <tab> sync-mailbox bind index <space> collapse-thread macro index,pager H view-mailcap bind index l display-message bind browser l select-entry bind index gl limit macro index gL "<limit>all\n" "show all messages (undo limit)" bind index \031 previous-undeleted # Mouse wheel bind index \005 next-undeleted # Mouse wheel bind browser,pager,index N search-opposite bind pager,index dT delete-thread bind pager,index dt delete-subthread bind pager,index gt next-thread bind pager,index gT previous-thread bind index za collapse-thread bind index zA collapse-all bind index - collapse-thread bind index _ collapse-all macro index \Cr "<tag-pattern>~U<enter>\ <tag-prefix><clear-flag>N<untag-pattern>.<enter>" \ "mark all messages as read" # m i s c bind browser,pager,index N search-opposite bind pager,index dT delete-thread bind pager,index dt delete-subthread bind pager,index gt next-thread bind pager,index gT previous-thread bind index,pager V view-raw-message macro index dd "<save-message>+Trash<enter><sync-mailbox>" "move message to Trash" bind pager,index D purge-message bind index,pager gr group-reply #R is recall postponed by mutt # p a g e r bind pager k previous-line bind pager j next-line bind pager l view-attachments bind pager R group-reply bind pager gg top bind pager G bottom bind pager,attach h exit bind pager \031 previous-line # Mouse wheel bind pager \005 next-line # Mouse wheel bind pager t display-toggle-weed # b r o w s e r bind browser gg top-page bind browser G bottom-page bind browser l select-entry # a t t a c h m e n t s bind attach l view-text bind attach <return> view-mailcap bind attach gg first-entry bind attach G last-entry bind attach l view-text bind attach <return> view-mailcap # e d i t o r bind editor <space> noop bind editor <Tab> complete-query # a d d r e s s b o o k macro index,pager a "<pipe-message>abook --add-email-quiet<return>" "Add this sender to Abook" # p g p bind compose p pgp-menu macro compose Y pfy "send mail without GPG" # m a i l b o x e s macro index <f4> '<sync-mailbox><enter-command>source ~/.mutt/accounts/mdir.riseup<enter><change-folder>!<enter>' macro index,pager c "<change-folder>?<toggle-mailboxes>" "open a different folder"
macro index,pager iqu "<change-folder>=Queue<enter>" "go to Queue" macro index,pager Mqu "<save-message>=Queue<enter>" "move mail to Queue" macro index,pager Cqu "<copy-message>=Queue<enter>" "copy mail to Queue"
macro index,pager itr "<change-folder>=Trash<enter>" "go to Trash" macro index,pager Mtr "<save-message>=Trash<enter>" "move mail to Trash" macro index,pager Ctr "<copy-message>=Trash<enter>" "copy mail to Trash"
macro index,pager isp "<change-folder>=Spam<enter>" "go to Spam" macro index,pager Msp "<save-message>=Spam<enter>" "move mail to Spam" macro index,pager Csp "<copy-message>=Spam<enter>" "copy mail to Spam"
macro index,pager iin "<change-folder>=INBOX<enter>" "go to INBOX" macro index,pager Min "<save-message>=INBOX<enter>" "move mail to INBOX" macro index,pager Cin "<copy-message>=INBOX<enter>" "copy mail to INBOX"
macro index,pager ise "<change-folder>=Sent<enter>" "go to Sent" macro index,pager Mse "<save-message>=Sent<enter>" "move mail to Sent" macro index,pager Cse "<copy-message>=Sent<enter>" "copy mail to Sent"
macro index,pager idr "<change-folder>=Drafts<enter>" "go to Drafts" macro index,pager Mdr "<save-message>=Drafts<enter>" "move mail to Drafts" macro index,pager Cdr "<copy-message>=Drafts<enter>" "copy mail to Drafts" # Fetch mail shortcut bind index G imap-fetch-mail
5. sidebar # =================== SIDEBAR PATCH ==================== # # l a y o u t set sidebar_visible = yes set sidebar_width = 12 set sidebar_short_path = yes set sidebar_next_new_wrap = yes set mail_check_stats set sidebar_format = '%B%?F? [%F]?%* %?N?%N/? %?S?%S?' set status_chars = " *%A" set status_format = "───[ Folder: %f ]───[%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]───%>─%?p?( %p postponed )?───" color sidebar_new color221 color233 # b i n d i n g s bind index,pager \Ck sidebar-prev bind index,pager \Cj sidebar-next bind index,pager \Co sidebar-open bind index,pager \Cl sidebar-open bind index,pager \Cp sidebar-prev-new bind index,pager \Cn sidebar-next-new macro index b "<enter-command>toggle sidebar_visible<enter>" # b toggles sidebar visibility macro pager b "<enter-command>toggle sidebar_visible<enter>" # b toggles sidebar visibility
6. theme
Take whatever theme you like and put it inside ~/.mutt/themes, then source it in ~/.mutt/muttrc, as shown above.
Some good ones are listed on the official colorschemes page: <https://neomutt.org/contrib/colorschemes>
As a final note, I'd change the permissions of ~/.msmtprc. ~/.mutt/muttrc, ~/.mutt/accounts/* and ~/.mutt/certificates to be 600. That's all folks, enjoy!