Mails, calendars, and contacts in one TUI.
Find a file
2026-08-17 00:29:42 +02:00
docs mail: adding support for storing mail text 2026-08-16 16:24:49 +02:00
src fix: redraw mail after reload 2026-08-17 00:29:42 +02:00
.gitignore initial commit 2026-08-15 21:46:16 +02:00
Cargo.lock initial commit 2026-08-15 21:46:16 +02:00
Cargo.toml adding local cache/storage for calendar and contacts 2026-08-16 00:48:45 +02:00
Makefile initial commit 2026-08-15 21:46:16 +02:00
README.md initial commit 2026-08-15 21:46:16 +02:00

office

A terminal client for mail, calendar and contacts — three sections in one binary, so that they know about one another.

Where it stands: mail really reads and writes. IMAP over TLS: the folder tree, the headers, the message text, \Seen and \Flagged written back to the server, deleting into the trash. Post goes out — SMTP over STARTTLS or TLS, the copy is filed in Sent, and whatever has not been sent yet sits on the server as a draft. New mail arrives by itselfIDLE keeps one connection open per mailbox — and when you happen to be elsewhere, the desktop says so. Several mailboxes, several sender addresses, set up in section 4 Settings.

Calendar and contacts come out of CalDAV and CardDAV, on the same rustls stack the mail does. An invitation that arrives as mail is answered in the calendar, and the address book completes a recipient — which is the whole reason the three are one program rather than three.

Installing

Rust 2024 edition and a terminal. TLS is rustls, so there is no system OpenSSL to link against and nothing else to install for mail, calendar or contacts to work.

make run          # run from source, debug profile
make build        # optimised binary in target/release/office
make install      # copy it to ~/.local/bin/office
make uninstall    # take it away again
make help         # every target, with a line each

Two things are optional, and the interface says so rather than failing when they are missing:

  • A keyring. Passwords go to the Secret Service on Linux (gnome-keyring, KWallet) or the Credential Manager on Windows. With no keyring running they are kept in the process for the session, and the Settings row reads · instead of ●●●●●●●● keyring. They are never written to the config file.
  • A notification daemon, for the desktop notice about new mail that arrives while you are looking at something else.

Set the terminal to a Nerd Font — the Mono cut. The four markers in the message list — unread, flagged, answered, attachment — are drawn from the Font Awesome block a Nerd Font patch adds, because the ordinary Unicode symbols for them are missing from most monospace fonts and the terminal then borrows each one from a different fallback, at a different size. Nothing else in the interface needs it.

Every patch ships three cuts, and the difference matters here: … Nerd Font Mono draws each icon inside one cell, while plain … Nerd Font and … Nerd Font Propo draw them at their natural width — wider than the one cell the terminal advances, so an icon laps over whatever is next to it. Pick the one ending in Mono.

Then start it and go to section 4 Settings — there is no configuration to write by hand. Configuration walks through the first account.


Documentation

Configuration accounts, senders, notifications, language, the config file, and the probe CLI
The sections mail, calendar, contacts, settings — and what ties them together
Keys and the mouse every binding, and the order a click is resolved in
What works the honest state of it, protocol by protocol
Layout the rules it is drawn by, and how to preview it
Libraries every dependency decision, and what connecting it taught

Development

make check              # cargo check --all-targets
make fmt-check lint test

Nothing in the test suite touches the network. cargo test -- --nocapture preview renders every section and overlay into a TestBackend and prints them, which is the fastest way to see a change without starting the app — Layout explains what it draws.