About Using the Terminal Email Clients

Dec 31st, 2025 @ bertyuan's web page

Although GitHub now occupies a large share of the market for code hosting services, many projects still prefer to use mailing list for communication and   patch submission.[1] In this post, I will outline my thoughts for using Aerc and NeoMutt configured with Mutt-Wizard.


Getting started

Please let me ramble on.
Aerc is available on most GNU/Linux distributions and macOS via Homebrew. (Sorry, no Windows here)
Check for official installation instructions of Aerc.
And the same for NeoMutt:
Check for official installation instructions of NeoMutt.

It is recommended to use Mutt-Wizard from Luke Smith to set up NeoMutt, which simplifies the configuration process significantly. But for those who prefer manual configuration, you can either set every component up, or use your own configuration files to override Mutt-Wizard's defaults.

My configurations

It is widely known that both Aerc and NeoMutt are customizable, especially NeoMutt.
Here I will list some of my configurations for reference.

Aerc

For Aerc, this is how the config file folder looks like:
> tree
.
├── accounts.conf
├── aerc.conf
├── binds.conf
└── stylesets # optional for custom stylesets
    └── foo

In accounts.conf, I add this line: copy-to-replied = true, to make threads in the same mailbox.
Or you can set threads by notmuch with its virtual folder feature. Then you do not need this config.
Therefore, I need to set up threads in aerc.conf as well:

threading-enabled=true

Also, I do not like the default setting of replying to self in Aerc, so I add this:

reply-to-self=false

In binds.conf, I set up some keybindings for convenience:

# make `d` to move to Trash
d = :read<Enter>:move Trash<Enter>

[messages:folder=Trash]
# d = :choose -o y 'Delete Forever' delete-message<Enter>
d = :prompt 'Delete Forever?' delete-message<Enter>

# mutt-like keybindings
l = :view
h = :close

The last one (optional) for Aerc is to set up a custom style in stylesets/foo:
Here's mine:

*.selected.bg = #1793D1 # arch blue
*.selected.fg = 15      # while or change to default
*.selected.bold = true
# Arch Linux blue borders
border.fg = #1793D1

And don't forget to source it in aerc.conf:

styleset-name=foo

NeoMutt

After setting up NeoMutt with Mutt-Wizard, I would like to make some changes to the default configuration, as the dafault ones are for Luke himself, not for me.
So I changed the colors first in ~/.config/mutt/muttrc:

# Default index colors:
color index white default '.*'
color index_author blue default '.*'
color index_number white default
color index_subject white default '.*'

color status color8 default
color sidebar_highlight blue default

Then the bindings:

bind index,pager \Cl list-reply
bind index,pager J sidebar-next # ======================================
bind index,pager K sidebar-prev # The same bingding as in Aerc,
bind index,pager L sidebar-open # while keeps the dafault ones from Mutt

Unfortunately, Mutt/NeoMutt does not support patch highlighting like Aerc does.
So I can only use this[2] to mannually highlight patches, though sometimes it would mistakely highlight non-patch emails:

# --------------
# Simple version
# --------------

# A
# color body yellow color234 "^(\>\ )*diff \-.*"
# color body yellow color234 "^(\>\ )*index [a-f0-9].*"
# color body yellow color234 "^\(\>\ )*\-\-\- .*"
# color body yellow color234 "^(\>\ )*[\+]{3} .*"
# color body brightgreen color234 "^(\>\ )*[\+].*"
# color body brightred color234 "^(\>\ )*[\-].*"

# B
# color body cyan color234 "^(\>\ )*@@ .*"
# color body green default "^diff \-.*"
# color body green default "^index [a-f0-9].*"
# color body green default "^\-\-\- .*"
# color body green default "^[\+]{3} .*"
# color body cyan default "^[\+][^\+]+.*"
# color body red  default "^\-[^\-]+.*"
# color body brightblue default "^@@ .*"

# -------------------
# Complicated version
# -------------------
# Patch syntax highlighting
#color   normal  white           default
color   body    brightwhite     default         ^[[:space:]].*
color   body    yellow          default         ^(diff).*
#color   body    white           default         ^[\-\-\-].*
#color   body    white           default         ^[\+\+\+].*
#color   body    green           default         ^[\+].*
#color   body    red             default         ^[\-].*
#color   body    brightblue      default         [@@].*
color   body    brightwhite     default         ^(\s).*
color   body    cyan            default         ^(Signed-off-by).*
color   body    cyan            default         ^(Docker-DCO-1.1-Signed-off-by).*
color   body    brightwhite     default         ^(Cc)
color   body    yellow          default         "^diff \-.*"
color   body    brightwhite     default         "^index [a-f0-9].*"
color   body    brightblue      default         "^---$"
color   body    white           default         "^\-\-\- .*"
color   body    white           default         "^[\+]{3} .*"
color   body    green           default         "^[\+][^\+]+.*"
color   body    red             default         "^\-[^\-]+.*"
color   body    brightblue      default         "^@@ .*"
color   body    green           default         "LGTM"
color   body    brightmagenta   default         "-- Commit Summary --"
color   body    brightmagenta   default         "-- File Changes --"
color   body    brightmagenta   default         "-- Patch Links --"
color   body    green           default         "^Merged #.*"
color   body    red             default         "^Closed #.*"
color   body    brightblue      default         "^Reply to this email.*"

UPDATE

# Default index colors:
color index white default '.*'
color index_author blue default '.*'
color index_number white default
color index_subject white default '.*'

color status color8 default
color sidebar_highlight blue default

# remove the ~T rule from mutt-wizard
uncolor index "~T"
uncolor index_author "~T"
uncolor index_subject "~T"
uncolor index_number "~T"

# replace the ~T rule with black text on white background
color index        none black white "~T"
color index_author none black white "~T"
color index_subject none black white "~T"
color index_number none black white "~T"


###############################################################################
# Take over ALL index colors (override mutt-wizard defaults)
###############################################################################

# 1) wipe mw's index-color rules
uncolor index        *
uncolor index_author *
uncolor index_subject *
uncolor index_number *

# 2) base scheme (apply to ALL mail)
color index         none white default ".*"
color index_author  none blue  default ".*"
color index_subject none white default ".*"
color index_number  none white default ".*"

# 3) NEW / UNREAD mail
color index         none white default "~N"
color index_author  none yellow  default "~N"
color index_subject none white default "~N"
color index_number  none white default "~N"

color index         none white default "~U"
color index_author  none yellow  default "~U"
color index_subject none white default "~U"
color index_number  none white default "~U"

# 4) FLAGGED mail
color index         none white default "~F"
color index_author  none blue  default "~F"
color index_subject none white default "~F"
color index_number  none white default "~F"

# 5) TAGGED mail ()
# Grey
color index         none white color8 "~T"
color index_author  none white color8 "~T"
color index_subject none white color8 "~T"
color index_number  none white color8 "~T"

# 6) Deleted mail = red text
color index         none white red "~D"
color index_author  none white red "~D"
color index_subject none white red "~D"
color index_number  none white red "~D"

# colors
# source ~/.config/mutt/mutt-colors-solarized-dark-16.muttrc
source ~/.config/mutt/mutt-patch-highlighting.muttrc
# source ~/.config/mutt/mutt-colors-steve-losh.muttrc
# source ~/.config/mutt/mutt-colors-neowolf-256.muttrc

Opinion

As Drew DeVault mentioned in his blog, the design/intention of "Always Online" is less than ideal when it comes to no internet connection scenarios. Frankly speaking, it rarely happens to me here in China. So I prefer using Aerc with its "Always Online" feature enabled. (though waiting for several seconds for connection is annoying compared to NeoMutt's offline mode) On the other hand, NeoMutt with Mutt-Wizard is a solid choice, when the Internet connection is unstable. Also as Drew DeVault said, you can use more than one email clients depending on your actual situation. So this is my strategy for using terminal email clients: use Aerc when the Internet connection is stable, and NeoMutt when it is not.

Expectations

I was wondering if there's a way that one email system can download emails from IMAP server to the local storage, so that when I open the email client, I can read emails offline without delay. After opening and showing all the local emails, the client would automatically sync with the server in the background, downloading new emails and uploading emails. If we could do this in the terminal email clients, that would be perfect. Or maybe it is already achieved? If you know how to do this, please let me know.

See also

1. The official website of Aerc
2. The official source code of Aerc
3. The official website of NeoMutt
4. The official repo of NeoMutt
5. aerc, mbsync, and postfix for maximum comfy offline email by Drew DeVault
6. Email with Aerc by Julio Loayzam
7. Configuring aerc for git via email by Drew DeVault
8. The advantages of an email-driven git workflow by Drew DeVault
9. Git send email tutorial
10. Initial pre-release of aerc: an email client for your terminal by Drew DeVault
11. Use Plaintext Email - A guide to using plain text email effectively
12. Mutt, Patches and GitHub by Yoshikee
13. Highlighted patches inside Mutt by Karel Zak
14. Email client (aerc)by Will Webberley
15. Sorting threads in NeoMutt


  1. Check this classic blog for more information about mailing lists vs GitHub.
  2. Originally from this.

Back to index