README.md
August 26, 2026 · View on GitHub
Caution
Neverest is in active development and currently shipped as v1.0.0-rc. Expect breaking changes between releases until stabilization.
Important
This README documents Neverest v1.0.0-rc, which is not released yet. Two releases exist: refer to the v1.0.0-beta README or the v0.1.0 README for the one you are running, and to MIGRATION.md for the upgrade path from either.
Table of contents
Features
- PIM domain support: mail via IMAP and Microsoft Graph (JMAP and Gmail configure but have no backend yet), contacts via CardDAV rfc6352 (requires the
carddavfeature); one account syncs several at once - Local pimdir store specs: the single local copy an app reads, holding every domain an account syncs
- Retention: a removed item is kept, never lost, and reclaimed on a schedule
- Relay mode: a body crossing two IMAP servers is streamed server-to-server, never stored
- Queued submission: a message a frontend enqueued leaves through its source's send channel
- Auth support: anonymous, login, plain, oauthbearer, xoauth2, scram-sha-256 for IMAP; basic and bearer for CardDAV; OAuth 2.0 bearer tokens for Microsoft Graph
- TLS support: Rustls with ring or aws crypto (
rustls-awsfeature), Native TLS (native-tlsfeature) - Discovery support: known provider rules, PACC specs, Autoconfiguration specs, SRV rfc6186, DAV rfc6764
- Interactive wizard turning an email address into a tested account
- TOML configuration with multi-account support, and JSON output via
--json
Tip
Neverest is written in Rust and uses cargo features to gate backend support. The default feature set is declared in Cargo.toml.
Installation
Pre-built binary
Neverest can be installed with the installer:
As root:
curl -sSL https://raw.githubusercontent.com/pimalaya/neverest/master/install.sh | sudo sh
As a regular user:
curl -sSL https://raw.githubusercontent.com/pimalaya/neverest/master/install.sh | PREFIX=~/.local sh
Neverest v1 is not released yet, so the installer has nothing to fetch. Until then, check out the releases GitHub workflow and look for the Artifacts section.
Note
Such binaries are built with the default cargo features. If you need specific features, please use another installation method.
Cargo
cargo install --locked --git https://github.com/pimalaya/neverest.git
With only IMAP support:
cargo install --locked --git https://github.com/pimalaya/neverest.git \
--no-default-features \
--features imap,smtp,rustls-ring
Nix
If you have the Flakes feature enabled:
nix profile install github:pimalaya/neverest
Or run without installing:
nix run github:pimalaya/neverest
Sources
git clone https://github.com/pimalaya/neverest
cd neverest
nix run
Configuration
A configuration is loaded from the first valid path among:
$XDG_CONFIG_HOME/neverest/config.toml$HOME/.config/neverest/config.toml$HOME/.neverestrc
Override the path with -c <PATH> or NEVEREST_CONFIG=<PATH>; multiple paths can be passed at once, separated by :. The first one is the base and the rest are deep-merged on top. The full field reference lives in config.sample.toml.
Run neverest with no configuration file on disk and a minimal wizard asks for an email address, searches the services reachable from it, prompts the authentication the chosen one advertises, tests the connection, then offers to write the result. It sets up one account with one backend, the offline replica most setups want, and nothing more: a second kind, a mirror between two providers, a fan-in are all written by hand against config.sample.toml. neverest configure runs the same flow again over an existing account. Declining the save prints the configuration on stdout, and a redirected stdout skips the prompts altogether, so neverest > config.toml writes the file itself.
An account is one pimdir store fed by one or more named sources, each a remote, and it may hold several kinds at once. Two sources of one kind mirror each other only where they share a collection.namespace; left alone they cache side by side and never push to one another. What the store keeps follows from that and is never configured, so every run and neverest check report it.
Usage
Every command carries its own --help, the source of truth for its flags and syntax.
neverest init -a <account>
neverest sync -a <account> --dry-run
neverest sync -a <account> --include-collection INBOX
neverest check -a <account>
An account is initialized once, which opens every source so credential and network errors surface up front, then creates the empty store. sync refuses to run without it, and init refuses to run over it. --reset drops the cached state before a run, rebuilding it as a first sync would.
Retention and backup
The store never truly deletes an item. When its last binding vanishes the row is retained: hidden from the sync and from listings, but kept with its body. Reclaiming is explicit and time-based, and neverest is the sweeper: after each sync it purges every retained item older than store.purge-after, then reports how many items and bytes it freed. Leaving the delay unset means never purge, "0" reproduces a terminal delete, and sync --no-purge skips the sweep for one run.
This is what turns a sync into a backup. Make the source read-only and leave store.purge-after unset: a remote expunge still retires the local row, but the item and its body stay in the store, restorable, and neverest never pushes a deletion back to the server.
[accounts.backup]
imap.server = "imaps://imap.example.org:993"
imap.item.delete = false
imap.collection.delete = false
Duplicated identities
A collection may hold one identity twice: two messages carrying the same Message-ID, two cards carrying the same UID. Neverest cannot tell such copies apart, so it syncs neither of them and reports the collection and every id involved, on every run until the collection holds the identity once. Which copy to keep is a decision only you can make, with your own client.
This is not an invalid mailbox, and nothing is wrong with your server. RFC 5322 binds the generator of a Message-ID, not what a store may hold: a copy legitimately carries the identifier of the message it copies, and a migration commonly produces such a pair. Reporting is what neverest does instead of guessing, because guessing costs mail. Propagating a delete of the copy it happened to pick removes the only copy on the other source while the first still holds the message.
Coming from Maildir
Neverest ships no Maildir converter, and a local file store is not a sync source: the pimdir store is the local replica. Keyword storage is not standardized across Maildir consumers (info-section letters, dovecot-keywords, X-Keywords and X-Label headers), so a local migration would silently lose or mangle flags depending on which tool wrote the source tree. Initialize a fresh account and resync from the authoritative server instead: flags re-converge cleanly and the store reflects the actual server state. An existing on-disk tree is brought in through io-pimdir's conversion tooling rather than synced as a source.
License
This project is licensed under either of:
Social
- Chat on Matrix
- News on Mastodon or RSS
- Mail at pimalaya.org@posteo.net
Sponsoring
Special thanks to the NLnet foundation and the European Commission that have been financially supporting the project for years:
- 2022 → 2023: NGI Assure
- 2023 → 2024: NGI Zero Entrust
- 2024 → 2026: NGI Zero Core
- 2026 → 2027: NGI Zero Commons Fund
This program is part of Pimalaya, free software funded entirely by grants and donations. If you find it useful, consider sponsoring its development:
