login

Mairix published on Jul 3, tagged with arch, bash, linux, mutt

Mairix is a nice little utility for indexing and searching your emails. Its smooth integration with mutt is also a plus.

I used to use native mutt search, but it’s pretty slow. So far, mairix is giving me a good approximation of the google-powered search available in the web interface and it’s damn fast.

As I go through this setup, keep in mind the example config files are designed to work with my overall mutt setup; one which is described in two other posts here and here.

If you need a little context, checkout my mutt-config repo which has a fully functioning ~/.mutt, example files for the other apps involved (offlineimap, msmtprc, and now mairix), and any scripts the setup needs.

Mairix

First, of course, install mairix:

pacman -S mairix

Then, setup a ~/.mairixrc which defines where your mails are and their type as well as where to store the results and index. Here’s an example:

# where you keep your mail
base=/home/<you>/Mail

# colon separated list of maildirs to index.
#
# I have two accounts each in their own subfolder. the '...' means there 
# are subdirectories to search as well; it's like saying GMail/* and 
# GMX/*
maildir=GMail...:GMX...

# I omit gmail's archive folder so as to pevent duplicate hits
omit=GMail/all_mail

# search results will be copied to base/<this folder> for viewing in 
# mutt
mfolder=mfolder

# and the path to the index itself
database=/home/<you>/Mail/.mairix_database

With that in place, run mairix once to build the initial index. This first run will be slower but in my tests, subsequent rebuilds were almost instant.

In situations like these, I’ll usually add a verbose flag so I can be sure things are working as expected.

At this point, you could actually do some searching right from the commandline:

mairix some search term # search and populate mfolder
mutt -f mfolder         # open it in mutt

This wasn’t the usage I was after however, I’m typically already in mutt when I want to search my mails.

Mutt

My original script for this purpose was pretty simple. It prompted for the search term and ran it. The problem was you then needed a separate keybind to actually view the results.

Thankfully, Scott commented and provided a more advanced script which got around this issue. Many thanks to Scott and whomever wrote the script in the first place.

This version does some manual tty trickery to build its own prompt, read your input, execute the search and open the results. All from just one keybind.

I merged the two scripts together into what you see below. The main changes from Scott’s version are the following:

  1. I kept my clear, purge, search method rather than relying on cron to keep the index up to date.
  2. I removed the append-search functionality; not my use-case.
  3. I removed the <return> from the ^G trap; it was getting executed by mutt and opening the first message in the inbox after a cancelled search.
  4. I fixed it so that backspace works properly in the prompt.

So, here it is:

#!/bin/bash

read_from_config() {
  local key="$1" config="$HOME/.mairixrc"

  sed '/^'"$key"'=\([^ ]*\) *.*$/!d; s//\1/g' "$config"
}

read -r base    < <(read_from_config 'base')
read -r mfolder < <(read_from_config 'mfolder')

# prevent rm / further down...
[[ -z "$base$mfolder" ]] && exit 1

searchdir="$base/$mfolder"

set -f                          # disable globbing.
exec < /dev/tty 3>&1 > /dev/tty # restore stdin/stdout to the terminal,
                                # fd 3 goes to mutt's backticks.
saved_tty_settings=$(stty -g)   # save tty settings before modifying
                                # them

# trap <Ctrl-G> to cancel search
trap '
  printf "\r"; tput ed; tput rc
  printf "/" >&3
  stty "$saved_tty_settings"
  exit
' INT TERM

# put the terminal in cooked mode. Set eof to <return> so that pressing
# <return> doesn't move the cursor to the next line. Disable <Ctrl-Z>
stty icanon echo -ctlecho crterase eof '^M' intr '^G' susp ''

set $(stty size) # retrieve the size of the screen
tput sc          # save cursor position
tput cup "$1" 0  # go to last line of the screen
tput ed          # clear and write prompt
tput sgr0
printf 'Mairix search for: '

# read from the terminal. We can't use "read" because, there won't be
# any NL in the input as <return> is eof.
search=$(dd count=1 2>/dev/null)

# clear the folder and execute a fresh search
( rm -rf "$searchdir"
  mairix -p
  mairix $search
) &>/dev/null

# fix the terminal
printf '\r'; tput ed; tput rc
stty "$saved_tty_settings"

# to be executed by mutt when we return
printf "<change-folder-readonly>=$mfolder<return>" >&3

A non-trivial macro provides the interface to the script. It sets a variable called my_cmd to the output of the script, which should be the actual change-folder command, then executes it.

macro generic ,s "<enter-command>set my_cmd = \`$HOME/.mutt/msearch\`<return><enter-command>push \$my_cmd<return>" "search messages"

I’ve gotten used to “comma-keybinds” from setting that as my localleader in vim. It’s nice because it very rarely conflicts with anything existing and it’s quite fast to type.

One downside which I’ve been unable to fix (and believe me, I’ve tried!) is that if you press ^G to cancel a search but you’ve typed a few letters into the prompt, mutt will read those letters as commands (via the push) and execute them.

The only thing I could do is prefix those characters with something. I’ve decided to use /. That makes mutt see it as a normal search which you can execute or ^G again to cancel. Annoying, but better than mutt flailing around executing rando commands…

I haven’t had the time yet to learn all the tricks, but here are some of the more useful-looking searches from man mairix:

Useful searches

   t:word                             Match word in the To: header.

   c:word                             Match word in the Cc: header.

   f:word                             Match word in the From: header.

   s:word                             Match word in the Subject: header.

   m:word                             Match word in the Message-ID: 

                                      header.

   b:word                             Match word in the message body 
                                      (text or html!)

   d:[start-datespec]-[end-datespec]  Match messages with Date: headers 
                                      lying in the specific range.

Multiple body parts may be grouped together, if a match in any of them 
is sought.

   tc:word  Match word in either the To: or Cc: headers (or both).

   bs:word  Match word in either the Subject: header or the message body 
            (or both).

   The a: search pattern is an abbreviation for tcf:; i.e. match the 
   word in the To:, Cc: or From: headers.  ("a" stands for "address" in 
   this case.)

The "word" argument to the search strings can take various forms.

   ~word        Match messages not containing the word.  

   word1,word2  This matches if both the words are matched in the 
                specified message part.

   word1/word2  This matches if either of the words are matched in the 
                specified message part.

   substring=   Match any word containing substring as a substring

   substring=N  Match any word containing substring, allowing up to N 
                errors in the match.

   ^substring=  Match any word containing substring as a substring, with 
                the requirement that substring occurs at the beginning 
                of the matched word.

Happy searching!

Notes published on Mar 26, 2011, tagged with bash, gmail, linux, mutt

For me, any sort of general purpose note taking and/or keeping solution needs to meet only a few requirements:

  1. Noting something has to be quick and easy (in a terminal and scriptable)
  2. Notes should be available from anywhere… tothecloud!
  3. Notes should be searchable

Now, just to clarify – I’m not talking about classroom notes, those things go in note-books. I’m talking about short little blurbs of information I would like to keep and reference at a later time.

Though, I suppose this could work for classroom notes too…

I’m also not talking about reminders, those are the stuff of calendars, not note-keeping apps.

So what’s my solution? What else, Gmail!

Gmail

Setting up gmail as a note keeper/searcher is simple. A note is an email from me with the prefix “Note -” in the subject line. Therefore, it’s easy to setup a label and a filter to funnel note-mails into a defined folder:

From:    me@whatever.com
Subject: ^Note - 

I also add “Skip inbox” and “Mark as read” as part of the rule.

I know the gmail filters support some level of regex and/or globbing, but I don’t know where it ends. I’m hoping that the ^ anchor is supported but I’m not positive.

Requirements 2 and 3 done.

Mutt

So if taking a note is done by just sending an email of a particular consistent format, then it’s easy for me to achieve requirement 1 since I use that awesome terminal mail client mutt.

A short bash function gives us uber-simple note taking abilities by handling the boilerplate of a note-mail:

noteit() {
  _have mutt || return 1 # see my dotfiles re: _have

  local subject="$*" message

  [[ -z "$subject" ]] && { echo 'no subject.'; return 1; }

  echo -e "^D to save, ^C to cancel\nNote:\n"

  message="$(cat)"

  [[ -z "$message" ]] && { echo 'no message.'; return 1; }

  # send message
  echo "$message" | mutt -s "Note - $subject" -- pbrisbin@gmail.com

  echo -e "\nnoted.\n"
}

You could probably also streamline note taking by leveraging mutt’s -H option. I’ll leave reading that man page snippet as an exercise to the reader.

And here’s how that might work out in the day-to-day:

//blue/0/~/ noteit test note
^D to save, ^C to cancel
Note:

This is a test note.

< I pressed ^D here >
noted.

//blue/0/~/

You could also use sendmail, mailx, msmtp or whatever other CLI mail solution you want for this.

And there it is, ready to be indexed by the almighty google:

Mutt notes shot

With a few mutt macros, I think this could get pretty featureful without a lot of code.

Let me know in the comments if there are any other simple or out-of-the-box note-keeping solutions you know of.

Oh, and before anyone mentions it – no, you can’t take notes without internet when you’re using this approach. I’m ok with that, I understand if you’re not.

Mutt + Gmail + Offlineimap published on Dec 5, 2009, tagged with linux, gmail, mutt

I’ve been using this email solution for some time now. My muttrc has been called both epic and awesome, so I figured I’d share my setup and how it got that way here.

What is it? A couple of applications working together to offer a simple, clean, usable way of interacting with my gmail account.

This post shares a lot of information with my second mutt post regarding multiple accounts accessed through mutt and offlineimap. If that’s something you’re planning on setting up you can skip this tutorial as it’s a subset of the information there.

Offlineimap syncs a local Maildir at ~/Mail with my gmail IMAP account every 3 minutes. I use mutt to interface with said Maildir, and msmtp to send email from mutt via gmail’s smtp server.

Full config files can be found in my mutt-config repo but I’ll post the important bits here.

Offlineimap

Step one is to setup Offlineimap to keep ~/Mail in sync with our gmail’s IMAP folder. This is a two way sync so anything moved, deleted, or sent from any IMAP-connected interface or our local mutt interface will act exactly the same. This also has the added benefit of storing offline, local copies of all your mails.

First, install Offlineimap and fill in an ~/.offlineimaprc like so:

[general]
# NOTE: cronjob calls the quiet UI with -u
ui = ttyui
accounts = GMail

[Account GMail]
localrepository = Gmail-Local
remoterepository = Gmail-Remote

[Repository Gmail-Local]
type = Maildir
localfolders = ~/Mail/GMail

[Repository Gmail-Remote]
type = Gmail 
remoteuser = username@gmail.com
remotepass = gmailpassword
realdelete = no

# "[Gmail]/Some Folder" --> some_folder
nametrans = lambda folder: re.sub('^inbox$', 'INBOX',
                           re.sub(' +', '_',
                           re.sub(r'.*/(.*)$', r'\1', folder).lower()))

# vim: ft=cfg tw=0

Take note of the nametrans. My line there will change folder names during the sync so IMAP/[Gmail].Archive becomes ~/Mail/archive and similar for all other folders. You can choose not to use this line if you don’t mind the default folder names, but you’ll have to be careful to use the right folder names in your ~/.muttrc.

Offlineimap is kind of buggy for me, if I use its built in refresh mechanism I find it’ll often hang or quit and I’ll be left with an unsynced mailbox. Therefore, I set offlineimap to never refresh and put a [re]start script in a cronjob to take care of it.

For now, you can test by running offlineimap -o.

Once you’re sure things are syncing fine, set up a cron job to run a script called mailrun.sh every 3 minutes:

crontab -e

# then add this:
*/3 * * * * /path/to/mailrun.sh

Then create that script with these contents:

#!/bin/bash

PID=$(pgrep offlineimap)

# the only time offlineimap has been still running after 3 minutes for 
# me is if it's frozen... we'll kill it and resync
[[ -n "$PID" ]] && kill $PID

offlineimap -o -u quiet &>/dev/null &

exit 0

And make it executable via chmod +x /path/to/mailrun.sh

You may have to restart cron for these changes to take affect

Msmtp

Now we need a way to send mails via gmail’s smtp server. I like msmtp, you can also use other smtp clients. If you choose to install msmtp, the config file is at ~/.msmtprc and should look like this:

# msmtp config file

account default 
host smtp.gmail.com
port 587
protocol smtp
auth on
from user@gmail.com
user user@gmail.com
password XXXXX
tls on
tls_nocertcheck

Mutt

Now the fun part! I don’t know how many hours I’ve spent in the past year fine tuning my muttrc, but it’ll never be done. Here are the parts required to get this setup working.

# options
set mbox_type   = Maildir               # mailbox type
set folder      = ~/Mail                # root folder
set spoolfile   = "+INBOX"              # inbox
set mbox        = "+archive"            # [Gmail]/All Mail
set postponed   = "+drafts"             # [Gmail]/Drafts
unset record                            # required to prevent duplicates in Sent

set sendmail    = /usr/bin/msmtp        # use msmtp 'default' account

# mailboxes
mailboxes +INBOX +archive +sent +drafts +spam +trash

# bindings
macro index D "<save-message>+trash<enter>"   "move message to the trash"
macro index S "<save-message>+spam<enter>"    "mark message as spam"

The above should be enough to get a connection and start sending/receiving mail, but here are some other must-have options that make it feel a bit more like gmail:

# main options
set realname            = "Real Name"                   # who am i?
set from                = "user@gmail.com"              # who am i?
set envelope_from                                       # which from?
set mail_check          = 0                             # check for mail always
unset move                                              # gmail does that
set delete                                              # don't ask, just do
unset confirmappend                                     # don't ask, just do!
set quit                                                # don't ask, just do!!
unset mark_old                                          # read/new is good enough for me

# index options
set sort                = threads                       # like gmail 
set sort_aux            = reverse-last-date-received    # like gmail
set sort_re                                             # thread based on reply_regexp

# pager
set pager_index_lines   = 8                             # show 8 messages when in pager
set pager_context       = 5                             # show five lines when skipping in pager
set pager_stop                                          # don't go to next message automatically
set menu_scroll                                         # scroll in menus 
set smart_wrap                                          # don't split words
set tilde                                               # show tildes like in vim
unset markers                                           # no ugly plus signs

# composing mail
set fcc_attach                                          # save attachments with the body
unset mime_forward                                      # forward attachments as part of body
set forward_format      = "Fwd: %s"                     # format for subject when forwarding
set include                                             # include message in replies
set forward_quote                                       # include message in forwards

# headers to show
ignore *                                                # ignore all headers
unignore from: to: cc: date: subject:                   # show only these
hdr_order from: to: cc: date: subject:                  # and in this order

I’ve left out quite a few tweaks in the above so that those who are happy with mutt’s very sane defaults aren’t overwhelmed. Keep in mind, man muttrc is a great command for when you’re bored.

That should do it. Hopefully this info will get you going in the right direction. You might notice my various mutt settings are spread across a few different files. These are then sourced in the main ~/.muttrc. You might also find this approach useful, or you can just put everything in one file.

Using Two IMAP Accounts in Mutt published on Dec 5, 2009, tagged with linux, gmail, mutt

Mutt can be really great with multiple accounts, but it’s not exactly intuitive to setup. Here I’ll document how I access my GMail and GMX email accounts together in one mutt instance. Three tools are in use in a setup like this:

  1. One to sync your IMAP accounts with local Maildir folders
  2. One to send mail via the appropriate smtp server
  3. Finally, one to interact with the synced folders, compose messages, and call the send application as needed

All of my live config files can always be found in my mutt config repo; there are many changes, additions, and better ways of doing things compared to what’s printed below.

Offlineimap

Offlineimap handles multiple accounts very well. Here’s my ~/.offlineimaprc set up to sync my GMail and GMX accounts into two local Maildir folders:

[general]
# NOTE: cronjob calls the quiet UI with -u
ui = ttyui
accounts = GMail,GMX

[Account GMail]
localrepository = Gmail-Local
remoterepository = Gmail-Remote

[Account GMX]
localrepository = GMX-Local
remoterepository = GMX-Remote

[Repository Gmail-Local]
type = Maildir
localfolders = ~/Mail/GMail

[Repository GMX-Local]
type = Maildir
localfolders = ~/Mail/GMX

[Repository Gmail-Remote]
type = Gmail 
remoteuser = username@gmail.com
remotepass = gmailpassword
realdelete = no

# "[Gmail]/Some Folder" --> some_folder
nametrans = lambda folder: re.sub('^inbox$', 'INBOX',
                           re.sub(' +', '_',
                           re.sub(r'.*/(.*)$', r'\1', folder).lower()))

[Repository GMX-Remote]
type = IMAP
remotehost = imap.gmx.com
remoteport = 143 
remoteuser = username@gmx.com
remotepass = gmxpassword

# vim: ft=cfg tw=0

Take note of the nametrans for gmail. My line there will change folder names during the sync so IMAP://[Gmail].All Mail becomes ~/Mail/GMail/archive and similar for all other folders. You can choose not to use this line if you don’t mind the default folder names, but you’ll have to be careful to use the right folder names in your ~/.mutt/muttrc.

Offlineimap is written in python, and any valid python can actually be used in that nametrans. In fact, my live config has a more compact version that uses a couple of other function calls to accomplish essentially the same translation.

The ui setting is also useful in that when you test or sync with offlineimap from a command prompt, you can view the output, but in our cronjob we can call -u quiet explicitly to suppress it; best of both worlds.

You can test your setup by running offlineimap -o to sync things once. It could take a while, but once done, you should have a nice folder structure like this:

Mail/
|-- GMX
|   |-- Archive
|   |-- Drafts
|   |-- INBOX
|   |-- Sent
|   |-- Spam
|   `-- Trash
`-- GMail
    |-- INBOX
    |-- archive
    |-- drafts
    |-- flagged
    |-- sent
    |-- spam
    `-- trash

Offlineimap is kind of buggy for me, if I use its built-in refresh mechanism I find it’ll often hang or quit and I’ll be left with an unsynced mailbox. Therefore, I cronned a [re]start script to take care of it.

Once you’re sure things are syncing fine, create a script with these contents:

#!/bin/bash

PID=$(pgrep offlineimap)

[[ -n "$PID" ]] && kill "$PID"

offlineimap -o -u quiet &>/dev/null &

exit 

Make it executable via chmod +x /path/to/mailrun.sh and set up a cron job to run it every 3 minutes:

crontab -e

# add this:
*/3 * * * * /path/to/mailrun.sh

You’ll likely have to restart cron for the changes to take effect.

This script checks if offlineimap is already running; there’s two ways one could handle it if a PID is found: one, offlineimap is still syncing since 3 minutes and we should just exit and let it finish. Or two, offlineimap hasn’t completed its sync in 3 minutes so it must be frozen, we should kill it and resync. I’ve landed on the latter but the choice is yours, just change && kill $PID to && exit 1 to be more patient than I.

Msmtp

Msmtp also handles multiple accounts very elegantly. Here’s my ~/.msmtprc set up to handle my gmail and gmx accounts:

# msmtp config file

account gmail 
host smtp.gmail.com
port 587
protocol smtp
auth on
from username@gmail.com
user username@gmail.com
password gmailpassword
tls on
tls_nocertcheck

account gmx
host mail.gmx.com
port 587
protocol smtp
auth on
from username@gmx.com
user username@gmx.com
password gmxpassword
tls on
tls_nocertcheck

account default : gmail

Now we can simply call msmtp -a gmail or msmtp -a gmx to use whichever account we want (default is gmail for me).

You should do a quick sanity check here that you can send some mail:

echo "Your howto is awesome, thanks" | msmtp -a gmail praise@pbrisbin.com
echo "Your howto sucks balls, doucher..." | msmtp -a gmx spam@pbrisbin.com

Just make sure you get no errors with either account.

Mutt

Now we bring it all together in mutt. I’m gonna show you pretty much my full muttrc, not all of it is needed (but I like it) so feel free to experiment on your own version.

I prefer to separate my config out into some logical pieces. So we need to setup some support files, a few of which I’m not going to go into because they’re totally dependant on you, just ensure that these exist if you plan on blindly copy/pasting large portions of my config:

# files
~/.mutt/certificates    # touch an empty file
~/.mutt/colors.muttrc   # define colors in muttrc syntax
~/.mutt/mailcap         # touch an empty file (go google if you want to utilize this)
~/.mutt/alias           # touch an empty file
~/.mutt/sig             # type a signature that'll be added to emails

# mkdir all these
~/.mutt/temp
~/.mutt/cache/bodies
~/.mutt/cache/headers

There is also a file I keep at ~/.mutt/sidebar.muttrc, with all of the sidebar-specific options in it, I do this so I can quickly comment the source line in ~/.mutt/muttrc if I take that config to a machine running vanilla mutt.

My live config loads this file only if mutt -h signifies that the sidebar patch is applied.

Now, the two supporting config files we need to pay attention to: These will be setup per account, with overriding settings. That way, we can define a folder-hook so that when we’re viewing mail in ~/Mail/GMail/* we have all of our gmail specific account settings loaded, and if we’re in ~/Mail/GMX/* we have all of our gmx settings loaded. These are things like our from address, where to store sent messages, where to put deleted messages, etc. Pretty cool, huh? I also put a quick color setting in each of these files so when we’re in gmail the statusbar is green, but when we’re in gmx, it’s cyan. I find this visual cue really useful.

So, setup two files, one at ~/.mutt/gmail.muttrc:

###
# gmail specific options
###

color status green default

set from      = "username@gmail.com"
set sendmail  = "/usr/bin/msmtp -a gmail"
set mbox      = "+GMail/archive"
unset record
set postponed = "+GMail/drafts"

macro index E "<change-folder>+GMail/archive<enter><limit>~B " "search everything"
macro index D "<save-message>+GMail/trash<enter>"              "move message to the trash"
macro index S "<save-message>+GMail/spam<enter>"               "mark message as spam"

And one at ~/.mutt/gmx.muttrc:

###
# gmx specific options
###

color status cyan default

set from      = "username@gmx.com"
set sendmail  = "/usr/bin/msmtp -a gmx"
set mbox      = "+GMX/Archive"
set record    = "+GMX/Sent"
set postponed = "+GMX/Drafts"

macro index E "<change-folder>+GMX/Archive<enter><limit>~B " "search everything"
macro index D "<save-message>+GMX/Trash<enter>"              "move message to the trash"
macro index S "<save-message>+GMX/Spam<enter>"               "mark message as spam"

Now the most important file of all: ~/.mutt/muttrc. Here is my complete muttrc, commented so you can tell what things do; I’m not explaining anything beyond the folder-hook. This means when we enter a folder, we load the settings specific to that account as defined above. This means there’s no need to change accounts per say, just navigate to a folder and any account specific settings will automatically be in place while you’re in that folder.

Go man muttrc if you’d like more info on all the other settings.

###
# ~/.mutt/muttrc
###

# directories and commands
set alias_file          = ~/.mutt/alias                         # alias file
set header_cache        = ~/.mutt/cache/headers                 # where to store headers        
set message_cachedir    = ~/.mutt/cache/bodies                  # where to store bodies
set certificate_file    = ~/.mutt/certificates                  # where to store certs
set mailcap_path        = ~/.mutt/mailcap                       # entrys for filetypes
set signature           = ~/.mutt/sig                           # my signature file
set tmpdir              = ~/.mutt/temp                          # where to keep temp files
set editor              = "/usr/bin/vim +/^$"                   # use vim and skip to first blank line

# main options
set mbox_type           = Maildir                               # mailbox type
set folder              = ~/Mail                                # mailbox location
set spoolfile           = "+GMail/INBOX"                        # GMail is default inbox
set timeout             = 3                                     # idle time before scanning
set mail_check          = 0                                     # minimum time between scans
set sort_alias          = alias                                 # sort alias file by alias
set reverse_alias                                               # show names from alias file in index
unset move                                                      # gmail does that
set delete                                                      # don't ask, just do
unset confirmappend                                             # don't ask, just do!
set quit                                                        # don't ask, just do!!
unset mark_old                                                  # read/new is good enough for me
set beep_new                                                    # bell on new mails
set pipe_decode                                                 # strip headers and eval mimes when piping
set thorough_search                                             # strip headers and eval mimes before searching

# index options
set sort                = threads                               # like gmail 
set sort_aux            = reverse-last-date-received            # like gmail
set uncollapse_jump                                             # don't collapse on an unread message 
set sort_re                                                     # thread based on regex
set reply_regexp        = "^(([Rr][Ee]?(\[[0-9]+\])?: *)?(\[[^]]+\] *)?)*"

# pager options
set pager_index_lines   = 10                                    # number of index lines to show 
set pager_context       = 5                                     # number of context lines to show
set pager_stop                                                  # don't go to next message automatically
set menu_scroll                                                 # scroll in menus 
set smart_wrap                                                  # don't split words
set tilde                                                       # show tildes like in vim
unset markers                                                   # no ugly plus signs
auto_view text/html                                             # view html automatically
alternative_order text/plain text/enriched text/html            # save html for last
set quote_regexp        = "^( {0,4}[>|:#%]| {0,4}[a-z0-9]+[>|]+)+"

# formats
set date_format         = "%m/%d/%y at %I:%M%P"
set index_format        = "%3C [%Z] %D %-15.15F %s"
set alias_format        = "%4n %t %-20a  %r"

# composing mail
set realname            = "Patrick Brisbin"                     # who am i?
set envelope_from                                               # which from?
set sig_dashes                                                  # dashes before my sig... sweet
set edit_headers                                                # show headers when composing
set fast_reply                                                  # skip to compose when replying
set sendmail_wait       = -1                                    # don't wait for sending... to complete
set askcc                                                       # ask for CC:
set fcc_attach                                                  # save attachments with the body
unset mime_forward                                              # forward attachments as part of body
set forward_format      = "Fwd: %s"                             # format for subject when forwarding
set forward_decode                                              # decode when forwarding
set attribution         = "On %d, %n wrote:"                    # set the attribution
set reply_to                                                    # reply to Reply to: field
set reverse_name                                                # reply as whomever it was to
set include                                                     # include message in replies
set forward_quote                                               # include message in forwards

# headers to show
ignore *                                                        # ignore all headers
unignore from: to: cc: date: subject:                           # show only these
hdr_order from: to: cc: date: subject:                          # and in this order

# boxes
mailboxes +GMail/INBOX +GMail/archive +GMail/sent +GMail/drafts +GMail/spam +GMail/trash
mailboxes +GMX/INBOX +GMX/Archive +GMX/Sent +GMX/Drafts +GMX/Spam +GMX/Trash

# always sourced
source $alias_file                                              # required for functionality
source ~/.mutt/colors.muttrc                                    # source colors file
source ~/.mutt/sidebar.muttrc                                   # any muttng options are here
source ~/.mutt/gmail.muttrc                                     # source gmail as default

# account specific sources
folder-hook GMail/* source ~/.mutt/gmail.muttrc
folder-hook GMX/*   source ~/.mutt/gmx.muttrc

# these just give me headaches
bind index,pager \#    noop
bind index i           noop

# bindings
bind pager i           exit
bind pager /           search
bind pager <up>        previous-line
bind pager <down>      next-line
bind pager k           previous-line
bind pager j           next-line
bind pager gg          top
bind pager G           bottom
bind index gg          first-entry
bind index G           last-entry
bind pager K           previous-undeleted
bind pager J           next-undeleted
bind index K           previous-unread
bind index J           next-unread
bind index,pager R     group-reply

# macros
macro index \Cr "<tag-prefix><clear-flag>N" "mark tagged messages as read"
macro index B   "<limit>~b "                "search message bodies"
macro index I   "<change-folder>!<enter>"   "go to Inbox"

# save a decoded copy in ~
macro index P   "<pipe-message>cat > ~/"    "save message as"

# quick-sync ~/Mail immediately with offlineimap
macro index Z   "<shell-escape>/usr/bin/offlineimap -q -o<enter>" "sync IMAP"

Now just send some mails back and forth between the two accounts to verify that the folder-hooks are setting the from address and such correctly.

Vim Tweaks

I also have the following tweaks in ~/.vimrc to help with my composing:

" Some tricks for mutt
" F1 through F3 re-wraps paragraphs in useful ways
augroup MUTT
  au BufRead ~/.mutt/temp/mutt* set spell " <-- vim 7 required
  au BufRead ~/.mutt/temp/mutt* nmap  <F1>  gqap
  au BufRead ~/.mutt/temp/mutt* nmap  <F2>  gqqj
  au BufRead ~/.mutt/temp/mutt* nmap  <F3>  kgqj
  au BufRead ~/.mutt/temp/mutt* map!  <F1>  <ESC>gqapi
  au BufRead ~/.mutt/temp/mutt* map!  <F2>  <ESC>gqqji
  au BufRead ~/.mutt/temp/mutt* map!  <F3>  <ESC>kgqji
augroup END

You’ll find a cleaner version of the above tweaks in my vim repo in the ftplugin/mail.vim file.

Well that’s it. Two IMAP accounts accessed easily, intuitively, and efficiently in your favorite email program.