Space Panda

Reading Mail

This is the fourth part in the series on Reading Mail in the Terminal.


For displaying email (neo)mutt uses the built-in pager (unless you configure an external pager through the pager setting) which is actually quite good, because it allows you to quickly access the attachments directly, or on the spot reply to the email.

There is a status line for the pager which can be reconfigured to display only the relevant information, like the sender, subject, and number of attachments. I’ll demonstrate two variants: one with and one without the use of nerd fonts:

# ~/.config/neomutt/neomuttrc

# sender, subject, right align, number of attachments, if any
set pager_format = " %n - %s %> %?X?@ %X?& "
# and again, this time with nerd fonts
set pager_format = "  %n  %s %> %?X?  %X ?"
neomutt showing a spam email with a modified pager_format using nerd fonts.

The status bar on top with nerdfont icons. This is also already using some colouring for the content.

It’s probably time to address the elephant in the room: yes, I’m not using the normal colour scheme, but solarized light. Setting that up in the console is easy enough, but where do the colors for the attachment information and the header come from?

Painting the Mail Red

(neo)mutt can be assigned colours to various parts of the UI by means of the color directive:

# ~/.config/neomutt/neomuttrc

color message     color0   color15
color hdrdefault  color14  color7
color signature   color0   color15
color attachment  color2   color15

Colours are set by object, foreground, background. In this example an attachment will have the foreground colour 2 (green) and background colour 15 (white). Only the header uses the darker variant of white (color 7).

But this is not where it stops. You can use regular expressions to colour parts of messages differently. For example you could highlight URLs and email addresses 1:

# ~/.config/neomutt/neomuttrc

color body   color4  color15  "<?(http|ftp)s?://[^ \n\t\r\)]+>?"
color body   color4  color15  "<?[a-zA-Z+\-_0-9\.]+@[a-zA-Z0-9_\.\-]+\.[a-zA-Z0-9]+>?"

Furthermore you can decide to give certain headers a different colour, again using regular expressions:

# ~/.config/neomutt/neomuttrc

color header  color0  color7  "^(Subject:)"
color header  color0  color7  "^(From:)"

And of course you can apply that newly found power for colouring everywhere else in (neo)mutt, too: in the index, in the attachments, etc.

Handling HTML Email

The pager only knows how to display plain text emails. Unfortunately, thanks to bad decisions on the end of software developers, many people send HTML-only emails. To still be able to read these more or less conveniently, I convert them to markdown.

In order to tell (neo)mutt how to convert HTML emails to markdown, you have to set up a so-called mailcap file. In this file you tell (neo)mutt how to open certain file types:

# ~/.config/neomutt/mailcap

text/html; ~/bin/html2text.py; copiousoutput;
text/plain; cat; copiousoutput;

copiousoutput tells (neo)mutt to copy the output of that program directly into the pager.

And here is the python script (that‘s really just a wrapper around html2text):

#!/usr/bin/env python3
# ~/bin/html2text.py

import sys
import html2text

raw = sys.stdin.buffer.read()
parser = html2text.HTML2Text()
parser.unicode_snob = True
parser.re_unescape = True
parser.skip_internal_links = True
parser.protect_links = True
parser.re_space = True
parser.use_automatic_links = False
parser.inline_links = False

html = None
for encoding  in ['utf_8', 'iso8859_15', 'utf16', 'cp1252', 'cp858', 'utf_32']:
    try:
        html = str(raw, encoding)
    except Exception as exc:
        continue
    else:
        break

if html is None:
    print('Failed to decode binary blob: could not find any sane encoding')
else:
    print(parser.handle(html))

Together with some reflowing options to make it easier to read emails with too long lines, it results in these configuration options:

# ~/.config/neomutt/neomuttrc

set pager_stop   = yes
set wrap         = 85
set reflow_text  = yes
set pager_format = "  %n  %s %> %?X?  %X ?"

set mailcap_path = "~/.config/neomutt/mailcap"

auto_view text/html
alternative_order text/plain text/markdown text/enriched text/html

pager_stop is quite useful unless you like to scroll to the next email when you pass the last line of the one you are currently reading.

You still have to set auto_view to text/html if you want the html2text.py script to kick into action.

Footnotes

1

The regex for email addresses is not working great yet, but as things go, it’s good enough for now.


Tagged as mail, neomutt