Install localmail
Install the localmail command-line tool
globally, point it at the Postgres database you created in Step 1, and
apply the schema migrations.
What you need
- A running Postgres database from Step 1 (you should know its DSN).
- Python 3.12 or newer — managed automatically
by
uv, you don't have to install Python yourself. - About 1 GB of disk for the Python environment and (later) the embedding model cache.
-
Install
uv.uvis a fast Python package manager from Astral. localmail uses it to manage its environment and provide a globally installed CLI.macOS / Linux:
curl -LsSf https://astral.sh/uv/install.sh | shWindows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"Open a new terminal so the updated
PATHtakes effect, then verify:uv --version -
Install the
localmailCLI.uv tool installinstalls a Python package and exposes its console scripts on yourPATH, in an isolated environment so it doesn't conflict with anything else.uv tool install \ --python 3.12 \ --from git+https://github.com/hherb/localmail \ localmailTo include the optional attachment-extraction dependencies (Docling, for higher-fidelity PDF parsing) install the
extractionextra:uv tool install \ --python 3.12 \ --from git+https://github.com/hherb/localmail \ --with 'localmail[extraction]' \ localmailVerify the binary is on your
PATH:localmail --version localmail --helpUpdating laterRe-run the same
uv tool installcommand with--reinstall, or simplyuv tool upgrade localmail. -
Create the config file.
localmail looks for
~/.config/localmail/config.tomlby default. Override with$LOCALMAIL_CONFIGorlocalmail --config PATH ….mkdir -p ~/.config/localmail curl -fLo ~/.config/localmail/config.toml \ https://raw.githubusercontent.com/hherb/localmail/main/config.example.tomlOpen the file in your editor and update the two required sections:
[database] # Match the DSN you verified in Step 1. URL-encode special chars in # the password (e.g. '@' -> %40, ':' -> %3A). dsn = "postgresql://localmail:local%40%40mail@localhost:5532/localmail" [attachments] # Where attachment blobs land on disk. ~/localmail is fine. Pick a # drive with room for the attachments your mail accounts will pull in. root = "~/localmail"Leave the
[daemon]block at its defaults for now. You will add[[accounts]]entries in Step 3, so don't worry about them yet. -
Apply the schema migrations.
This is the first command that actually touches the database. It is idempotent — re-running it never harms anything.
localmail init-dbYou should see one line per migration applied (
0001_init.sql…0017_messages_body_lang_pending_index.sqlat the time of writing) and a finalOK.If init-db failsThe most common cause is a wrong DSN: typo, wrong port, password not URL-encoded. Test the DSN with
psqlfirst using the exact connection string fromconfig.toml. The second most common cause is thepgvectorextension not being installed (see Step 1). -
Confirm everything is wired up.
localmail list-accountsYou should get an empty list with no error. That's expected — you haven't added any accounts yet. Connecting to Postgres is the only thing this command tries to do, so a clean run here means the DSN, schema, and CLI all line up correctly.
What the install gave you
| Path | What lives there |
|---|---|
~/.local/bin/localmail |
The CLI entry point. uv tool install placed it here. |
~/.config/localmail/config.toml |
Your topology — DSN, attachments root, daemon settings, accounts. |
~/localmail/blobs/ |
Empty for now. Attachments will land here, organised by SHA-256. |
| OS keyring (Keychain / Secret Service) | Where passwords and OAuth refresh tokens will be stored — not in any file. |
Postgres database localmail |
Schema is now in place. Empty tables until the first sync. |
Alternative: install from a checkout
If you want to hack on localmail or track a specific branch, clone the
repository and use uv sync instead:
git clone https://github.com/hherb/localmail
cd localmail
uv sync # installs deps into .venv
uv run localmail --help # invoke through uv run
uv run localmail init-db
Every command in this manual still works — just prefix it with
uv run.