# alot: a terminal mail client built on the notmuch index

> alot is a terminal based mail user agent that sits on top of the notmuch mail indexer, with a modular, command prompt driven interface built in Python on the urwid toolkit. It offers multiple sending accounts, PGP and MIME support, Python hooks on events, and a database manager that keeps a write queue so that new mail is not indexed while it is being read.

**pazz/alot** — Terminal-based Mail User Agent

- Repository: https://github.com/pazz/alot
- Stars: 749 · Forks: 166
- Language: Python
- License: GPL-3.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/pazz-alot

## A MUA on top of notmuch

alot is a terminal based mail user agent based on the notmuch mail indexer, and it is written in Python using the urwid toolkit. The stated goal is a modular, command prompt driven interface that provides a full MUA experience as an alternative to the Emacs mode shipped with notmuch.

That last clause is the whole positioning. notmuch is famously a mail indexer with an Emacs interface, and that interface is powerful in the way Emacs interfaces are, which is to say it assumes you already live in Emacs. alot is the alternative for people who want the same index, the same queries, and the same speed, in a different terminal.

So the architecture is a division of labour. notmuch owns the indexing, the searching, and the tagging, and it owns the database. alot owns the interaction: the buffers, the prompts, the key handling, the composing of messages, and the sending.

The project is GPL-3.0-or-later licensed, and the licence file in the repository is a COPYING file rather than a LICENSE file, which is the older convention. The last push was on 2026-10-18, and the releases are v0.12 from 2025-12-11, v0.11 from 2024-08-26, and 0.10 from 2021-09-26, so the version has been at zero for a long time and moves when something changes rather than on a schedule.

The package metadata names the author, Patrick Totzke, and a maintainer, Lucas Hoffmann, and marks the development status as Beta with a console environment classifier, which is the classification a terminal application should have.

## The feature list, and the parts that are not standard

The notable features list is long, and most of it is standard for a mail user agent. There are multiple accounts for sending mail, via sendmail. There is forwarding, replying, and group reply. There is printing and piping of mails and threads. There is a configurable status bar with notification popups, and there is tab completion and usage help for all commands.

Four of them are less common and are the reason to look at this project rather than any other terminal mailer.

The first is the database manager that manages a write queue to the notmuch index. notmuch is a reader that wants an up to date index, and a mail client that changes tags as you read creates a conflict, so alot does not write to the index directly while you work. It queues the changes and applies them, which is the difference between a client that is safe to use and one that corrupts a tag.

The second is the support for spawning terminal windows for asynchronous editing of mails. You compose a message, you leave it in an editor in another window, and the client carries on, which is a different model from a modal editor inside the interface.

The third is the Python hooks to react on events and do custom formatting. The extension mechanism is code, and it runs in the client, so it can do anything Python can do to a message before it is displayed.

The fourth is the full support for PGP and MIME encryption and signing, which for a terminal client means encryption is not a bolt-on from an external agent but part of the composition flow.

The contacts completion using customizable lookups commands is also worth a mention, because the address book is not hardcoded, it is a command you configure, which means it can come from whatever your system already has.

## Buffers, modes, and the prompt

The basic usage section is short, and it explains the interaction model better than a description of the features would.

The arrow keys, the page up and page down keys, the letters j and k, and the space bar move the focus. Escape cancels a prompt and Enter selects. And you can hit the colon key at any time and type a command into the prompt.

The interface shows one buffer at a time. Tab and Shift-Tab switch between them, the letter d closes the current buffer, and the semicolon lists them all.

What makes this usable is that the buffer type, or mode, is displayed at the bottom left, and it determines which prompt commands are available. That is a small design decision with a large effect, because it means the same key press does different things in a thread list and in a compose buffer, and the interface tells you which context you are in.

The help system follows the same model. Usage information on any command is listed by typing the word help followed by the command name, and the key bindings for the current mode are listed by pressing the question mark.

So the client is not a set of hardcoded keystrokes with a few escape hatches. It is a prompt driven interface where the keyboard is the fast path and the prompt is the general one, and the mode tells you which grammar you are currently typing in.

## Packaging, and the dependencies that matter

The packaging is ordinary setuptools with a version derived from the source control tag, and the dependency list is short enough to read in one go, which is unusual for a mail client.

The dependencies are notmuch2 at a recent version, which is the indexer and therefore the foundation. urwid and urwidtrees are the widget toolkit and its tree extension, which is what a text user interface is built from. python-magic does file type detection, which matters for a mail client deciding how to display an attachment. configobj handles the configuration files, including the user configurable keyboard maps and the colour and layout themes. gpg is the encryption and signing library, which is why the PGP and MIME support is a first class feature rather than an integration. And standard-mailcap is a dependency for Python versions above 3.12, which is the mechanism that lets the client find the program to open a given attachment type.

The optional dependency groups are the conventional ones. Sphinx for the documentation, pytest for the tests, and mypy for the typing.

The type checking setup is worth noting, because the mypy configuration is specific rather than nominal. It targets Python 3.10, it warns on returning any, it checks untyped definitions, it warns on redundant casts and on unused ignores, and it shows error codes. The Ruff configuration even has a per file exception, because one documentation generator has to import the package before the source tree is on the path.

The repository layout matches the shape of the application, with the package itself, the documentation, an extra directory, the tests, a NEWS file, and a flake.nix with a lock file, which means the project can be built with Nix as well as with pip.

## Documentation, hooks, and the people behind it

The installation and customisation section is a signpost rather than a guide, and it points at three things.

The user manual has installation notes, advanced usage, customisation, hacking guides, and a frequently asked questions section. The wiki collects user contributed hooks and hacks. And the feature requests are tracked as issues with a label, which is a light way of running a wish list for a project with a volunteer maintainer.

The wiki is the more interesting of the three, because it is where the Python hooks live in practice. The hook mechanism is the extension point, and the wiki is where the community publishes the ones people actually use, so a new user gets the benefit of other people's customisation without having to write any.

The community channel is an IRC channel, and the README invites you to hang out there, ask questions, and make suggestions, as well as opening issues and pull requests on the GitHub page. A project with a libera.chat channel and a wiki of hooks is a community project in the older and more social sense, which is a different kind of asset from the code.

For a reader deciding whether to try it, that matters. alot is not a product with a support desk, it is a mail client for people who already know notmuch, and the audience is assumed rather than sold to.

## Who it is for, and what to check before you install

The decision to use alot is mostly a decision about notmuch, and it is worth being explicit about that.

If you already run notmuch, if you have a large mail archive indexed, and you are the kind of person who prefers a command prompt to a mouse, then alot gives you a fast mail client over an index you already trust, and the write queue design means reading mail will not fight with your tagging.

If you do not run notmuch, then alot is a much larger commitment than a mail client, because you are also committing to running and maintaining an indexer over your mail store, and to thinking in terms of queries rather than folders. The README is honest that this is an alternative to the Emacs mode shipped with notmuch, which is a description of a niche.

There is also a security dimension, because a mail client handles hostile input. The PGP and MIME support is a feature and a liability at the same time, and the decision about whether to verify signatures by default is a policy question that the hooks and the configuration are there to answer.

Before installing, the checklist is short. Have notmuch installed and indexed, with a recent enough version. Have gpg available with a version above 1.10, since it is a hard dependency. Be aware that the mailcap handling changes with the Python version, so the Python 3.12 boundary is not a formality. Read the hooks wiki, because the extension model is Python code running inside the client, and read the frequently asked questions page, which is where the practical answers live.

And then judge the interface on its own terms. It is a prompt driven client with modes and buffers, which is a fast and complete way to work, and it is not what you get with a graphical mailer. That is a feature for one person and a wall for another.

## Conclusion

alot fits a Linux user who already runs notmuch, who wants a readable mail client in a terminal rather than a web or desktop one, and who is comfortable with a command prompt driven interface. It does not fit someone who wants a graphical mail client, and it does not fit a setup without notmuch, since the indexer is the foundation rather than an optional extra. Verify first that notmuch is installed and indexed, that the gpg version and the mailcap handling match your system, since both are runtime dependencies rather than conveniences, and that you read the hooks and hacks wiki before you start writing your own, because the extension mechanism is Python and it is the part of the project most people customise.

## FAQ

### What is the alot mail client?

It is a terminal based mail user agent based on the notmuch mail indexer, written in Python with the urwid toolkit, and it provides a modular, command prompt driven interface as an alternative to the Emacs mode shipped with notmuch.

### How do I move around in the alot interface?

The arrow keys, page up and down, j, k, and space move the focus, Escape cancels a prompt and Enter selects, and the colon key opens the command prompt at any time. You can use Tab and Shift-Tab to switch between buffers, d to close the current one, and the semicolon to list them all.

### What are the standout features of alot?

A database manager that keeps a write queue to the notmuch index, the ability to spawn terminal windows for asynchronous mail editing, Python hooks that react to events and do custom formatting, full support for PGP and MIME encryption and signing, multiple sending accounts via sendmail, and contacts completion through configurable lookup commands.

### What does alot need installed to work?

The runtime dependencies are notmuch2, urwid and urwidtrees, python-magic, configobj, gpg, and standard-mailcap on Python versions above 3.12. Python 3.10 or newer is required, and the optional extras are Sphinx for the docs, pytest for the tests, and mypy for the typing.

### How do I get help with alot?

The user manual covers installation, advanced usage, customisation, and hacking guides, the wiki collects user contributed hooks and hacks, and the developers hang out in the channel on the libera.chat IRC server. Type the help command followed by a command name at the prompt for usage information on that command, and press the question mark for the key bindings of the current mode.

## Sources

- [Issues](https://github.com/pazz/alot/issues)
- [License: GPL-3.0](https://github.com/pazz/alot/blob/main/LICENSE)
- [pazz/alot on GitHub](https://github.com/pazz/alot)
- [README](https://github.com/pazz/alot/blob/main/README.md)
- [Releases](https://github.com/pazz/alot/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pazz-alot
