Database Configuration

Madmail stores accounts, settings, quotas, tokens, and federation state in one application SQL database: SQLite (default) or PostgreSQL. Mail bodies stay on disk as Maildir. Contact-sharing pages use a separate SQLite file (sharing.db).

MySQL is not supported. Changing driver does not copy an existing SQLite file by itself. After you edit driver / dsn, restart the process — madmail reload does not re-open the database.

SQLite (default)

madmail install always writes driver sqlite3. The file path follows your state_dir.

auth.pass_table local_authdb {
    table sql_table {
        driver sqlite3
        dsn /var/lib/madmail/credentials.db
        table_name passwords
    }
}

PostgreSQL (empty database)

Create an empty database and a role that can create tables. Set both auth.pass_table and storage.imapsql to the same Postgres driver and DSN (v2 opens the auth DSN; keeping both in sync avoids a misleading config).

CREATE USER madmail WITH PASSWORD 'choose-a-secret';
CREATE DATABASE madmail OWNER madmail;

Example in madmail.conf:

auth.pass_table local_authdb {
    auto_create yes
    jit_domain $(primary_domain)
    table sql_table {
        driver postgres
        dsn host=127.0.0.1 port=5432 user=madmail password=choose-a-secret dbname=madmail sslmode=disable
        table_name passwords
    }
}

storage.imapsql local_mailboxes {
    auto_create yes
    driver postgres
    dsn host=127.0.0.1 port=5432 user=madmail password=choose-a-secret dbname=madmail sslmode=disable
    retention 24h
    default_quota 1G
    appendlimit 100M
}

URL form is also accepted: postgres://madmail:choose-a-secret@127.0.0.1:5432/madmail?sslmode=disable.

Then restart Madmail. First start against empty Postgres applies sqlx migrations. You do not run GORM or create quotas / contacts by hand.

Copy SQLite → PostgreSQL

Stop the server so SQLite is idle, then:

madmail db sqlite-to-postgres --dsn 'host=127.0.0.1 user=madmail dbname=madmail sslmode=disable' --dry-run
madmail db sqlite-to-postgres --dsn 'host=127.0.0.1 user=madmail dbname=madmail sslmode=disable' -y

After the copy, set driver postgres as above and start the server. This copies application tables only. It does not move Maildir, the retry queue, admin_token, or sharing.db, and it does not rewrite madmail.conf. If Postgres already has password rows, pass --force.

In-memory caches vs on-disk state

For performance, the running server may keep a copy of credential rows (auth.pass_table) and per-user quota totals (storage.imapsql) in RAM. The authoritative data remains in the database.

If you change those databases with the CLI (for example madmail creds, madmail accounts, or madmail imap-acct) while the daemon stays up, call the Admin API resource POST /admin/cache/reload once so the process re-reads the tables. Alternatively, restart the service.