Open-source project
meli/meli avatar
meli/meli

meli: a terminal mail client for IMAP, JMAP, Maildir and Usenet

terminal mail client, mirror of https://git.meli-email.org/meli/meli.git https://crates.io/crates/meli

900 stars30 forksRustGPL-3.0

At a glance

What is it?
meli is a Rust terminal email client that speaks IMAP, JMAP, Maildir, mbox, notmuch and NNTP, ships as a single binary with a compile-time feature set, and is packaged by most Linux distributions. It is a GPL-3.0 project whose canonical repository lives on a self-hosted forge, with GitHub, Codeberg and GitLab as mirrors.
Who is it for?
Adopt meli if you live in a terminal, you read mail over IMAP or JMAP, and you want a client that does not need a browser engine or a proprietary sync service. Do not adopt it if you need a graphical client, if you are not comfortable with a configuration file, or if you rely on a hosted calendar or contacts integration that a terminal client will not provide.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem: a mail client that is not a browser in disguise

Modern mail clients are applications that happen to display mail, and they bring with them a browser engine, a sync service, a telemetry conversation and a licence you did not choose. If you read your mail on a machine you administer, in a terminal, alongside ssh sessions and tmux, that is a lot of machinery for reading text.

meli is a BSD, Linux and macOS terminal email client with support for multiple accounts and for Maildir, mbox, notmuch, IMAP, JMAP and NNTP for Usenet. The project was established in 2017 and is written in Rust, with a minimum supported Rust version of 1.88.0. The homepage is meli-email.org, and the canonical repository is on the project's own forge at git.meli-email.org, with mirrors on GitHub, Codeberg and GitLab.

The audience is terminal users, which shows in the details. There is an IRC channel on OFTC, a Matrix bridge, mailing lists, and even an old, self-described as outdated but online and interactive web demo powered by WebAssembly, which is a nice piece of engineering curiosity: a terminal application compiled to WebAssembly and running in a browser.

The licence is GPL-3.0, with the COPYING file in the repository root, and the last push was on 2026-10-19. The published releases are v0.8.13 and v0.8.12, both dated 2026-01-05, and v0.8.11 from 2025-04-21, so the version line is still in the zero series.

The backend matrix, and the difference between reading and sending

The feature that defines meli is the number of ways it can get mail into the terminal.

The reading backends are Maildir, mbox, notmuch, IMAP, JMAP and NNTP for Usenet. Maildir and mbox are the local Unix formats, and notmuch is the search index that many people already run over their local mail. IMAP is the network protocol almost every provider supports, and JMAP is the newer standard that meli supports as a first class backend rather than as an afterthought.

The submission backends are a separate axis, because reading and sending have very different requirements. Sending mail means dealing with a server, authentication and a queue, so the SMTP support is a client, described in the project documentation as an integrated async SMTP client.

That separation is what makes the client usable in mixed environments. Someone who reads mail from a local Maildir and sends through a corporate relay is a common case, and a client that insists on one protocol for both is awkward. Here the local format and the SMTP server are independent choices.

The topic list also names imap-client, jmap, nntp-client, notmuch, mbox and mua, which describes the same set from the library angle. And the type registries are separate from the account configuration, which is what allows one binary to serve a local-only setup and a multi-account IMAP setup at the same time.

Compile-time features, and what the default build already includes

meli is configurable at build time through cargo features, and the default set is worth reading before you install:

toml
default = ["sqlite3", "notmuch", "smtp", "dbus-notifications", "gpgme", "cli-docs", "jmap", "static"]

That is eight features, and the list explains a lot about the design. sqlite3 pulls in the rusqlite crate with the bundled-full feature and is used in the caches. notmuch depends on the maildir feature and provides the notmuch backend. smtp depends on the tls feature and brings the async SMTP client. jmap depends on the http feature and the url crate with serde, and provides the JMAP backend. dbus-notifications is how the client notifies your desktop, gpgme is the GnuPG interface for message signing and encryption, cli-docs builds the command line documentation, and static links the binary statically.

Two of those deserve a comment. The sqlite3 feature is about caching rather than about your mail store, and the static feature is what makes the pre-built static binaries possible, since a dynamically linked binary would need the libraries present on the target machine.

The point of the feature system is that a minimal install is possible. A user who only wants IMAP over a terminal, with no GnuPG, no desktop notifications, no notmuch and no JMAP can turn those off, and the project documents each flag with its dependencies and notes.

The consequence for a packager is that the feature set becomes part of the package definition, and the Makefile reads it from an environment variable, so a distribution build can differ from a local one without a fork.

Installing: cargo, the distributions, and static binaries

The number of installation routes is a sign of a project that has been around long enough to be packaged everywhere. The shortest is cargo, and the documentation gives the released crate and the development snapshot separately:

sh
cargo install meli
sh
cargo install --git https://git.meli-email.org/meli/meli.git meli

The distributions are the other half. Debian and its derivatives package it, and the install is:

sh
apt install meli

Alpine Linux packages it too:

sh
apk install meli

and macOS has both Homebrew and MacPorts:

sh
brew install meli
sh
port install meli

There is also an AUR package for Arch, an openSUSE package, a pkgsrc port for NetBSD, an OpenBSD port, and a Nix package in nixpkgs. The repology status table linked from the documentation shows the versions in each repository, which is the fastest way to see how far behind a given distribution is.

For people who do not want a package manager at all, the project publishes pre-built Debian packages with static binaries for the amd64 and arm64 architectures on its GitHub releases page.

Building from source is either make or:

sh
cargo build --release --bin meli

with detailed instructions in BUILD.md and the Makefile help output as the map. The Makefile is POSIX shell, installs to a prefix with a bin directory and a man directory, and the manpages it installs are:

sh
MANPAGES ?= meli.1 meli.conf.5 meli-themes.5 meli.7

Four separate man pages for the program, the configuration file, the themes and the general documentation is a level of polish that says the configuration format is meant to be learned rather than guessed.

The workspace: meli the application, melib the library

The Cargo.toml declares a workspace with two members:

toml
[workspace]
resolver = "2"

members = ["meli", "melib"]

The split is the interesting part. melib is the library layer, holding the backend abstractions and the account handling, and meli is the terminal user interface built on top of it. That separation is what allows other projects to reuse the protocol implementations, and it is why the feature flags live in one place and apply to both.

The dependency list in the workspace section is small and tells you what kind of program this is. There is serde with serde_derive and serde_json for configuration and data, nom for parsing, futures and smol for the async runtime, indexmap and smallvec for ordered and compact collections, uuid for identifiers, tempfile for tests, and serde_test2 for serialisation tests. There is no GTK, no ncurses and no terminal framework, which is consistent with a client that renders its own text.

The release profile is tuned for a distributable binary. Fat link time optimisation, a single codegen unit, opt-level of s for size, debug information off and symbols stripped.

toml
[profile.release]
lto = "fat"
codegen-units = 1
opt-level = "s"
debug = false
strip = true

That profile exists for the static builds, and it is also what makes the binary pleasant to ship in a distribution: one file, no runtime dependency on the user's Rust toolchain or shared libraries.

The linting rules, which are unusually strict for a project this size

The workspace lint configuration is one of the more revealing files in the repository. The Clippy lint groups are all denied, and they are the strict ones: correctness, suspicious, complexity, perf, cargo, nursery and style. On top of that, individual lints are denied by name, including large_include_file, print_stdout, print_stderr, todo, unimplemented, dbg_macro, rc_buffer and as_underscore.

Two of those are worth understanding. Denying print_stdout and print_stderr in a terminal program means every piece of output goes through the logging layer, which is how a client can be run inside a pipeline without its status messages corrupting the data. And denying todo and unimplemented means a function that is not finished is a compile error rather than a surprise at runtime.

The Rust lints are set too, with unsafe_op_in_unsafe_fn denied, and the rustdoc lints redundant_explicit_links and broken_intra_doc_links denied, so the documentation cannot rot into broken links.

The Makefile adds the compiler flags for the same purpose:

sh
RUSTFLAGS ?= -D warnings -W unreachable-pub -W rust-2021-compatibility

Warnings are errors, unreachable public items are warned about, and the 2021 edition compatibility lint is enabled.

Around this there is the rest of the engineering apparatus: a fuzz/ directory, a Cross.toml for cross compilation, a deny.toml for cargo-deny to check licences and advisories of dependencies, a cliff.toml for generating the changelog, codemeta.json for citation metadata, a .clippy.toml, a .gdbinit, a scripts/ and tools/ directory, a debian/ directory for packaging, and a contrib/ directory.

Licence, governance and the cases where meli is the wrong tool

The licence is GPL-3.0, and the repository carries the full text in COPYING along with a CONTRIBUTING.md, a DEVELOPMENT.md and a BUILD.md. The project distributes itself under it and the Makefile header repeats the terms. For a personal mail client that is uncontroversial; for a company that wants to embed the client in a product, the copyleft is the thing to read before anything else, and this is not legal advice.

The governance detail is the repository hosting. The canonical repository is on the project's own forge at git.meli-email.org, with the issue tracker there as well, and the GitHub, Codeberg and GitLab repositories are described as official mirrors. The tooling follows: there is a .gitea/ directory, which is the forge's own continuous integration configuration, and the mirror list is published in the documentation. That is a deliberate choice by a project that has existed since 2017 and has seen hosting policies change.

Where meli is the wrong tool is straightforward. If you want a graphical client, this is not it, and the terminal UI is not a thin skin over a GUI toolkit, it is a text rendering with its own key bindings. If you are not comfortable editing a configuration file and learning keymaps, the setup cost is real even though the configuration is documented in a manual page. If your mail life depends on a hosted calendar, contact sync or a vendor specific conversation view, a terminal client will not reproduce those.

The alternative approach is worth naming as well. A graphical client makes the same protocol decisions differently, wrapping a mailbox in widgets and a notifications system, and a mail reader built on a pager over a local Maildir makes a different set of assumptions again, treating the index as text to be searched rather than a protocol to be synchronised. The choice is not really about features. It is about whether your mail is a document you read or a service you log into, and meli is built for the second reading, with the first available in a different tool.

Editorial conclusion

Adopt meli if you live in a terminal, you read mail over IMAP or JMAP, and you want a client that does not need a browser engine or a proprietary sync service. Do not adopt it if you need a graphical client, if you are not comfortable with a configuration file, or if you rely on a hosted calendar or contacts integration that a terminal client will not provide. Before you install, decide which backends you need and check the feature flags that provide them, because the default build already includes sqlite3, notmuch, smtp, dbus-notifications, gpgme, cli-docs, jmap and static, and building a leaner client means opting out of those.

Frequently asked questions

How do I install meli?

The shortest route is cargo install meli, or cargo install --git https://git.meli-email.org/meli/meli.git meli for the development snapshot. It is also packaged for Debian and Ubuntu with apt install meli, for Alpine with apk install meli, and for macOS with brew install meli or port install meli, with AUR, openSUSE, pkgsrc, OpenBSD and Nix packages as well.

Which mail backends does meli support?

The reading backends are Maildir, mbox, notmuch, IMAP, JMAP and NNTP for Usenet, and the submission side is handled by an integrated async SMTP client. The project documentation treats reading and sending backends as separate axes of configuration.

What cargo features does meli build with by default?

The default feature set is sqlite3, notmuch, smtp, dbus-notifications, gpgme, cli-docs, jmap and static, which pulls in the rusqlite crate for caches, the notmuch backend, the async SMTP client, JMAP support, GnuPG support and a statically linked binary.

Where is the canonical source for meli?

The main repository and issue tracker are at git.meli-email.org/meli/meli, with official mirrors on GitHub, Codeberg and GitLab. The project was established in 2017 and the minimum supported Rust version is 1.88.0.

What licence is meli released under?

GPL-3.0, with the full text in the COPYING file at the root of the repository. The Makefile and the project documentation both carry the same terms.

Official sources

  1. License: GPL-3.0
  2. meli/meli on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/meli-meli.svg)](https://hysenlabs.com/projects/meli-meli)

Was this useful?