Lumail - The console email client

This project is now archived, and "complete". See #361 for more details.


The core idea behind lumail, and the reason for writing it rather than continuing to extend the legacy-project, is that all the items that are involved are Objects.

When you're writing configuration functions you should only be dealing with simple objects, such as:

By making all the basic things objects, and simplifying our API we've got a mail-client which is simple to script, and has a unified feel. There is no need for a large number of global-functions, just a few types of objects and ways to create/access them.


The mail-client is written in C++ and generally defers to the Lua code to perform actions.

There are some cases though where Lua is specifically invoked from the C++ core in the style of a traditionally callback:

The default lua configuration file will also invoke call-backup functions when some actions take place:

These functions may be defined by the user, and will be invoked if present.


The Config object allows you to get, set, and iterate over configuration values.

A configuration variable will have both a name and a value, and we support the use of several different types for the value:

The following (static) methods are available:

If the function Config:key_changed is defined it will be invoked whenever the value of a key is changed. The function will be given two arguments:

NOTE: We've defined a helper method in global.config.lua which allows you to retrieve the value of a configuration-key and return a default value if the key is not set.

  function Config.get_with_default(key,default)

Sample code is available in sample.lua/config.lua.

Configuration Variables

We have a number of variables which are special, the most important ones are:

For each mode that has a display there will be a $mode.max to store the count of the objects, as well as $mode.current.

So if the current mode is maildir then:

The global ARGS table contains all arguments passed to the command-line, and can be used for your own purposes.

For day to day usage some variables change the way that the client displays things, these are:

The default behaviour of the gpg support can be configured with:


The following (static) methods exist:

Sample code is available in sample.lua/file.lua.


The following (static) methods exist:

Sample code is available in sample.lua/file.lua.

Global State

There are some things which are global, and these largely revolve around available maildirs, and messages.

There is the notion that a message might be selected, and similarly a maildir.

The following API methods are available to help you with this:

Logfile Usage

There is a simple primitive for writing messages to a logfile, which can be useful for debugging.

By default log-entries are not written, to enable them you must set a filename like so:

 Config:set( "log.path" , "/path/to/log" )
 Config:set( "log.level" , "lua|startup|debug" )

To log all messages, which will be noisy:

 Config:set( "log.level", "all");

Once a filename has been set logs may be added via:

 Log:log( "debug", "This is a debug message" )
 Log:log( "lua",  "This is a lua message" )


You can gain access to Maildir objects in several ways:

The Maildir object has the following methods:


The Message object represents a single message, contained within a maildir.

You can get access to message objects in several ways:

Message methods:


MessagePart objects are returned from the parts() method. The MessagePart object contains the following methods:

Sample code is available in sample.lua/show_message.lua.


There is a simple helper-object allowing you to retrieve the MIME-type of files, based upon their contents. This lookup is achieved via libmagic.

Sample code is available in sample.lua/mime_type.lua.


There is only a single networking method:

Sample code is available in sample.lua/net.lua.

Regular Expressions

There is a thin wrapper around PCRE for those who prefer this family of regular expressions. The single method is:

The return value will vary depending on the regexp:

Sample code is available under sample.code/regexp.lua.


The Screen object is registered automatically and doesn't need to be constructed The following (static) methods are available:

Sample code is available in sample.lua/screen.lua.

Sorting Messages

The sorting of messages is implemented in C++, but uses the Lua functionality to ensure the user can influence the behaviour.

The sorting method is stored in the variable index.sort, which will select the appropriate Lua callback function to perform the sorting.

For example:

(i.e. "compare_by_XXX" is invoked when index.sort is XXX.)

To define your local sorting solution you should:

The threads sorting method groups the messages into threads before running the callback function defined in the config value threads.sort.

The Panel

The screen has an associated status-panel, hereby referred to as the panel.

The panel is designed to collect & contain output messages for the user. New entries may be appended to it at any time, and the most recent N entries are displayed - the number being dependent upon the height of the panel.

The Panel object has the following (static) methods:

Sample code is available in sample.lua/panel.lua.


The core of the application invokes the lua function on_idle() once per second, when the system is idle. The default implementation of this on_idle function will invoke any defined user timers, which are regular Lua functions which have a particular naming scheme.

In your configuration file define an ordinary function with a name matching the pattern on_XX - where XX is an integer.

For example:


Each of the major modes is implemented in a combination of Lua and C++.

On the C++ side there is a virtual class instantiated which has the following two methods:

On the Lua side each mode will call a method like:

These methods must return a table of lines, which will then be displayed. The lines may contain a prefix containing colour information. For example:

function lua_view()
  local r = { "$[RED]This is red",
              "$[YELLOW]This is yellow!" }
  return r

The function lua_view generates the output used in Lua-mode, one of the many available modal view-modes.