Configuration¶
Client Configuration¶
The CLI reads a client config file for mail list and mail read defaults, so you don't need to pass the mailbox directory every time.
Location: $XDG_CONFIG_HOME/titlani/config.toml (default: ~/.config/titlani/config.toml)
[mail]¶
| Field | Type | Required | Description |
|---|---|---|---|
mailbox_dir |
string | yes | Path to the directory containing mailbox subdirectories |
Example¶
With this config in place, the following commands work without explicit paths:
titlani mail list # lists messages for $USER in /var/mail/misfin
titlani mail read 2 # reads message #2 from the listing
The config file is optional. If absent, you must pass mailbox_dir as a CLI argument.
Server Configuration¶
The Titlani server is configured via a TOML file with eight sections.
[server]¶
Core server settings.
| Field | Type | Default | Description |
|---|---|---|---|
host |
string | "localhost" |
Bind address |
port |
int | 1958 |
Listen port (must be 1-65535) |
hostname |
string | "localhost" |
Hostname for mail routing (must match recipient addresses) |
certfile |
string | — | Path to TLS certificate PEM file |
keyfile |
string | — | Path to TLS private key PEM file |
mailbox_dir |
string | "mailboxes" |
Directory containing mailbox subdirectories |
identity_certfile |
string | — | Path to server identity certificate |
identity_keyfile |
string | — | Path to server identity private key |
identity_cert_dir |
string | <mailbox_dir> |
Directory for per-mailbox identity certificates (used by GMAP for client cert authentication) |
Note
If certfile/keyfile are omitted, temporary TLS certificates are auto-generated.
If identity_certfile/identity_keyfile are omitted, a temporary identity for postmaster@<hostname> is auto-generated.
[rate_limit]¶
Token bucket rate limiting per client IP.
| Field | Type | Default | Description |
|---|---|---|---|
enable |
bool | false |
Enable rate limiting |
capacity |
int | 10 |
Maximum tokens in bucket |
refill_rate |
float | 1.0 |
Tokens added per second |
retry_after |
int | 30 |
Suggested retry delay in seconds (sent in status 44 response) |
[access_control]¶
IP-based access control.
| Field | Type | Default | Description |
|---|---|---|---|
enable |
bool | false |
Enable access control |
allow_list |
list[string] | [] |
IPs or CIDRs to always allow |
deny_list |
list[string] | [] |
IPs or CIDRs to always deny |
default_allow |
bool | true |
Allow IPs not in either list |
Allow list takes priority over deny list.
[verification]¶
Sender verification. See Sender Verification for details.
| Field | Type | Default | Description |
|---|---|---|---|
mode |
string | "off" |
Verification mode: "off", "optional", or "required" |
method |
string | "probe" |
Verification method: "probe" or "spki" |
cache_path |
string | <mailbox_dir>/verification_cache.db |
Path to SQLite verification cache |
cache_ttl |
int | 604800 |
Cache time-to-live in seconds (default: 7 days) |
probe_timeout |
float | 10.0 |
Timeout in seconds for verification probes and SPKI connections |
spki_on_change |
string | "reject" |
Action when a server's SPKI changes: "reject" or "accept" |
[encryption]¶
At-rest encryption for stored messages. See At-Rest Encryption for setup details.
| Field | Type | Default | Description |
|---|---|---|---|
enable |
bool | false |
Enable at-rest encryption |
key_dir |
string | <mailbox_dir> |
Directory containing <mailbox>.enc.pub public key files |
When enabled, the server scans for <mailbox>.enc.pub files in key_dir. Mailboxes with a public key get encrypted storage (.gemmail.enc); mailboxes without a key store messages as plaintext.
Note
The server loads only public keys for encryption. Private keys (.enc.key) remain user-owned and are used only by the CLI for decryption.
[gmap]¶
GMAP (Gemini Mailbox Access Protocol) for remote mailbox access. See GMAP for details.
| Field | Type | Default | Description |
|---|---|---|---|
enable |
bool | false |
Enable GMAP on a separate port |
port |
int | 1960 |
GMAP listen port (must be 1-65535) |
When enabled, the server starts a second TLS listener on the GMAP port that requests client certificates. Clients authenticate with their Misfin identity certificate (fingerprint-verified) to access their mailbox remotely.
[auto_reply]¶
Server-side auto-reply for out-of-office messages. See Auto-Reply for setup details.
| Field | Type | Default | Description |
|---|---|---|---|
enable |
bool | false |
Enable auto-reply |
interval |
int | 86400 |
Minimum seconds between auto-replies to the same sender |
When enabled, the server checks for a .auto-reply file in the recipient's mailbox directory after each delivery. If present, it sends the file contents as a reply with subject [Auto-Reply]. Requires identity_certfile and identity_keyfile to be configured in [server].
[lists]¶
Mailing list support. See Mailing Lists for setup details.
| Field | Type | Default | Description |
|---|---|---|---|
enable |
bool | false |
Enable mailing list forwarding |
archive |
bool | true |
Store a copy of forwarded messages in the list mailbox |
When enabled, any mailbox directory containing a subscribers.txt file is treated as a mailing list. Incoming messages are forwarded to all subscribers. The server auto-generates an identity certificate for each list to use when forwarding.
Full Example¶
[server]
host = "0.0.0.0"
port = 1958
hostname = "mail.example.com"
certfile = "server.pem"
keyfile = "server.key"
mailbox_dir = "/var/mail/misfin"
identity_certfile = "identity.pem"
identity_keyfile = "identity.key"
[rate_limit]
enable = true
capacity = 20
refill_rate = 2.0
retry_after = 15
[access_control]
enable = true
allow_list = ["192.168.0.0/16"]
deny_list = ["10.0.0.99"]
default_allow = false
[verification]
mode = "optional"
method = "probe"
probe_timeout = 5.0
[encryption]
enable = true
key_dir = "/etc/titlani/keys"
[gmap]
enable = true
port = 1960
[auto_reply]
enable = true
interval = 86400
[lists]
enable = true
archive = true
Validation¶
ServerConfig.validate() checks:
- Port is between 1 and 65535
- GMAP port is between 1 and 65535
- Certificate files exist if specified
- Key files exist if specified
- Verification mode is one of
"off","optional", or"required"