Lumail - The console email client

Examples of Lua functions

lumail has an embedded Lua interpreter which is used to configure keybindings, perform general configuration, & etc.

If you're new to Lua you might find the Lua website and the Lua Unofficial FAQ useful resources.

NOTE: Lumail-legacy has been superseded by Lumail 2.x, which has a wholly unified Lua API.

Writing useful functions

Using the supplied primitives you can write many interesting functions to interact with your messages/maildirs.

Here we show several examples of the kind of things that lumail allows:

address-book - TAB-completion

This example shows how you can add address-books to your TAB-completion set, so that when you're composing a mail you can easily enter recipient addresses.

Apply actions only if particular maildirs exist

If you wish to have the same lumail configuration files across a number of hosts you might find it useful to define code that executes only if particular Maildirs exist.

This brief example shows how that can be done.


Every morning I receive a bunch of messages which are filed away automatically, and there are some folders which I just ignore. This function will iterate over a small number of folders, matching a pattern, and mark each messages as read within them.


This example shows how to dump a list of unread-messages to disk. The dump includes unread mail from all Maildirs.


Internally lumail keeps a collection of variables which are made available to Lua. This function dumps them to a temporary file on-disk.


The get_signature() function is called prior to a mail being opened in your editor for composition.

This example shows how you can usefully and dynamically select the appropriate .signature file for the mail.


Lumail allows multiple folders to be opened at once, and via the index_limit() primitive you can cause the list of messages to show those which are new. Together these two things allow you to write the global_unread() method.

This function shows all currently unread messages, regardless of their folder.

HTML email handling

This function shows how to convert HTML-emails to plain text, via "lynx -dump".

load_state() & save_state()

You'll notice that many operations require saving state before completing them, and restoring that state afterward. These two helper functions save all useful state, and later allow it to be restored.


This is related to the daily() example listed above. Instead of blindly marking all messages as read it marks messages as read, in folders, if they match a given pattern.


This function will mark all messages in the currently open maildir, or series of maildirs, as being read.


This function reads X-Remote-IP header form a message, which I've configured my mailserver to populate with the IP address of the mail-server which sent me a mail.

Once the remote IP address has been found it is appended to a local blacklist.

Trash() handling

This example shows how to save messages to a Trash folder, instead of deleting them entirely.


This example demonstrates a simple menu to automatically open the attachments associated with a message with the correct application.

Remember you can invoke any function you've defined by pressing : and entering it in the prompt. (For example you could press ":" then enter "mark_all_read()".)

Binding keypresses to functions

All keybindings are configured by making entries in the global keymap. There are four entries in the keymap:

  • Entries that apply in all modes.
  • Entries that apply in maildir-mode.
  • Entries that apply in index-mode.
  • Entries that apply in message-mode.

With the previous mark_all_read function you would probably prefer to make it execute only in index-mode:

keymap['index']['R'] = 'mark_all_read();'

This will invoke the function if you press "R" in the index-view only; in all other modes the keypress "R" will do nothing.

Responding to events

lumail has several defined callbacks which are listed in the primitive list, each one is named "on_XXXX".

For example when reading a message the function on_read_message() is called if you define it.

If you're missing a handler that you think would be useful please report a bug.