Skip to content


Subversion checkout URL

You can clone with
Download ZIP
a console mail user agent
Ruby Shell
Branch: master


coma - a console mail user agent



This is coma, a simple but powerful console mail user agent. You can think of it as a modern (that is, post-2000) alternative to the venerable MH, RAND Mail Handler.

coma aims to provide a surrogate for MH that works well in modern environments. The main differences are:

  • coma uses Maildir as backing store; this is more reliable and widely supported.

  • coma has built-in MIME and UTF-8 support.

  • coma has built-in threading support (using jwz's algorithm).

  • coma is a single, extensible script written in Ruby, so you can implement complex features in it easily without having to write C.

Yet, coma also is a lot like MH:

  • it is command-driven, featuring a non-captive interface, unlike tools like mailx or mutt. It is well suited for parallel use for multiple terminals and thus a good fit for screen/tmux/xterms.

  • it is a MUA only. Mail delivery and transfer is the task of other tools.

Command-line parsing

coma is a multi-call script that is executed like this:


Note that some flags have *possibly several arguments*. Consider:

% coma repl -cc -att *.c -noquote


How do you use coma? The default workflow for coma works like this:

  • You are bored and want to read mail, or your xlbiff pops up and shows an interesting message.

  • Thus, you check your folders for new Maildir messages:

    % coma inc
    +INBOX              134 messages   129 unread     5 new
  • You setup a reading sequence you want to progress in; usually this is saved in your config, here is an explicit variant:

    % coma read +INBOX +ruby-talk thread unseen
    [...scan lines of new mail...]

    By default, “inc” sets up a reading sequence containing all fresh mail.

  • You read the mails:

    % coma show
    % coma next
    % coma next
    % coma next
    % coma next
    no more mail
  • You are done.

  • It is highly advised that you alias ,=coma.

Searching mail

coma has a powerful search language that can operate on the header fields being cached:

% coma scan '+INBOX ( subj:foo | subj:bar ) date>2009-01-01 unreplied'

For content searches, I recommend using mairix:

% mairix -r SEARCH TERMS | coma read -

Put the included “coma-search” wrapper into your path to simply use:

% coma search SEARCH TERMS

Sending mail

% coma mail ... [-cc ...] [-bcc ...] [-att ...]

% coma repl

% coma fwd

Other commands

% coma
Subcommands: att copy cur expunge folders fwd inc mail mark mkdir move
  next prev read repl scan seqs show usage

Folder list:

% coma folders
+camping-list         1299 messages     0 unread     0 new
+lispmachines          121 messages     0 unread     0 new

Marking mails:

% coma mark unseen -seen
% coma mark 666 667 -flagged

Deleting mail:

% coma mark 666 667 -trashed
% coma expunge

Moving and copying mail:

% coma move "date<2000-01-01" +archive
% coma copy +announcements   # defaults to .

Reading attachments:

% coma show
From: Dyers Downin <XXX>
Subject: " "You shall judge for yourself. It is just as Harvey
To: Etchells Freid <XXX>
Date: Mon, 19 Jul 2010 09:12:01 +0200

2 --image 19968B PNG 366x275 mousiness.png--
% coma att
1  multipart/mixed 27522B
2    image/png 19968B "mousiness.png"
% coma att 2
% display mousiness.png
% coma att 2 - |lpr

Scanning mail (like read, but don't change the current sequence):

% coma scan date   # sort by date

scan (and read) support various scan line formats, others can be implemented easily:

% coma scan 363 367 1133
 363  2008-01-10  Jeremy McAnally    Keeping Camping going                      
 367  2008-04-07  _why                   camping moved to github                
1133  2010-06-30  Magnus Holm        Access to               
% coma scan "363 367 1133" -fmt nmh
 363  01/10  Jeremy McAnally    Keeping Camping going<<all, I'm not sure who Cam
 367  04/07  _why               camping moved to github<<the better interest of 
1133  06/30  Magnus Holm        Access to<<I've converted the
% coma scan 363 367 1133 -fmt twoline
 363 Keeping Camping going                      
   S 2008-01-10 05:29  "Jeremy McAnally" <>
 367     camping moved to github                
   S 2008-04-07 21:17  _why <>
1133 Access to               
   S 2010-06-30 13:18  Magnus Holm <>
% coma scan "363 367 1133" -fmt 9fans  

Keeping Camping going                                                           
   363    Jeremy McAnally                        Thu, 10 Jan 2008 05:29:17 +0100
   367    _why                                   Mon, 07 Apr 2008 21:17:01 +0200

Access to                                                    
  1133    Magnus Holm                            Wed, 30 Jun 2010 13:18:49 +0200
% coma scan 363 367 1133 -fmt mailx
    363 Jeremy McAnally     Thu Jan 10 05:29 Keeping Camping going              
    367 _why                Mon Apr 07 21:17     camping moved to github        
   1133 Magnus Holm         Wed Jun 30 13:18 Access to

Working with sequences

Sequences are refered to in the query language as “%sequencename”. By default, you operate on the sequence “%default” (or $COMASEQ if set). You can list sequences with “coma seqs”:

% coma seqs
%default         1250 messages
%ten               10 messages
%y                 14 messages

Sequences are created with “coma scan … -save sequencename”, and can be deleted with “coma seqs -clear sequencename…”. You can add mails to a sequence with “coma scan … -add sequencename” or remove mails with “coma scan … -delete sequencename”.

There are two special sequences, “%” and “%-” which are the sequence expressions of the current and the last “coma read”, respectively.

Config file

You can create a ~/.config/coma/config like this:

path: /path/to/your/maildirs
scan: -default -arguments -for -scan
%alias: %for +often +needed %sequence +expressions


Ruby 1.8 and sqlite3.

External tools: file(1), w3m(1) for HTML mail display, identify(1) for images.

ZSH integration

. coma.zshrc


tkma provides a very early exmh-like interface for coma. Needs Tk.


Written by Christian Neukirchen <>.

To the extent possible under law, the creator of this work has waived all copyright and related or neighboring rights to this work.

Something went wrong with that request. Please try again.