Install
Quickstart
Run the container or the binary behind HTTPS, with a master key and storage.
What every deployment needs
-
A public HTTPS URL. MCP clients and your browser must reach the server, and OAuth requires HTTPS outside
localhost. Terminate TLS in a reverse proxy (Caddy, nginx, Traefik) or use a host that provides it. SetPOSTKEEP_PUBLIC_URLto the origin only, such ashttps://mail.example.com, with no path. -
A master key. It encrypts stored app passwords, Microsoft and Google tokens, webhook secrets and stored webhook events (AES-256-GCM). Generate one and keep a backup:
docker run --rm postkeep/postkeep generate-key # or: postkeep generate-key, or: openssl rand -hex 32Pass it as
POSTKEEP_MASTER_KEY, or put it in a file and setPOSTKEEP_MASTER_KEY_FILE(works well with Docker, Kubernetes and systemd secrets). If the key is lost or changed, none of these can be decrypted: every user must connect again, and webhook secrets and queued events are lost. To change the key without that, rotate it (see configuration). -
Persistent storage. By default the server uses a SQLite file (
/data/postkeep.dbin the image), so mount a volume at/data. Upgrading from 0.2.x with the default SQLite path: 0.3.0 looks forpostkeep.db, so rename your existing database file topostkeep.db(in the image,/data/postkeep.db) or pointPOSTKEEP_DATABASE_URLat it before starting. Account-page users sign in again once. If 0.3.0 has already started and created an emptypostkeep.db, stop it and replace that file with your old one. For several replicas or hosts without disks, use PostgreSQL:POSTKEEP_DATABASE_URL=postgres://user:password@host/db. When the database is remote, add?sslmode=verify-full. That checks the server certificate and host name against the webpki roots compiled into the binary.sslmode=requireencrypts without that check. If the provider uses a private CA, also addsslrootcert=/path/ca.pem(a PEM file the process can read). The schema is created and migrated automatically at startup. Each instance opens at most 10 database connections (POSTKEEP_DATABASE_MAX_CONNECTIONS). Behind a proxy or pooler that closes connections, recycle them sooner. For example, Fly Managed Postgres recommends a 300-second idle timeout and a 600-second lifetime (Fly), so setPOSTKEEP_DATABASE_IDLE_TIMEOUT=300andPOSTKEEP_DATABASE_MAX_LIFETIME=600. These are examples, not defaults. Migrations run at start. Behind a transaction pooler, run them on a direct connection instead: setPOSTKEEP_DATABASE_MIGRATE_URLto it, runpostkeep migrateas a release command (it exits 0 when there is nothing to do), and setPOSTKEEP_DATABASE_MIGRATE_ON_START=falseso the server refuses to start on a schema it has not seen.
Recommended: set POSTKEEP_ALLOWED_EMAILS to the addresses that may
connect. Without it, anyone who can reach the server can connect any
mailbox it accepts: iCloud, Fastmail and Yahoo by default, Outlook or
Gmail when those OAuth apps are set up, and any IMAP server you configured.
Run it
Docker
# 1. Generate a master key and keep a copy somewhere safe
docker run --rm postkeep/postkeep generate-key
# 2. Start the server behind your HTTPS proxy
docker run -d --name postkeep -p 127.0.0.1:8080:8080 \
-v postkeep:/data \
-e POSTKEEP_PUBLIC_URL=https://mail.example.com \
-e POSTKEEP_MASTER_KEY=<the key> \
-e POSTKEEP_ALLOWED_EMAILS[email protected] \
postkeep/postkeepDocker ComposeCompose
# App plus Caddy, which gets the HTTPS certificate for you
git clone https://gitlab.com/postkeep/postkeep.git
cd postkeep/deploy/compose
cp .env.example .env && chmod 600 .env
# edit .env: PUBLIC_URL, MASTER_KEY, ALLOWED_EMAILS, DOMAIN
docker compose --profile caddy up -dBinary
# Rust 1.94 or newer
cargo build --release
./target/release/postkeep generate-key > master.key
export POSTKEEP_PUBLIC_URL=https://mail.example.com
export POSTKEEP_MASTER_KEY_FILE=$PWD/master.key
export POSTKEEP_ALLOWED_EMAILS[email protected]
./target/release/postkeep serveThe full list of variables is in configuration
and in postkeep serve --help.
Connect your agent app
Agent apps that support remote (Streamable HTTP) MCP servers with OAuth sign-in connect to your server’s MCP endpoint:
https://mail.example.com/mcpThe client discovers the authorization server, identifies itself (with a
client metadata document at an https URL, or by registering) and opens
the sign-in page in your browser. There you sign in with your mailbox:
Sign in with Microsoft or Sign in with Google, or your iCloud,
Fastmail or Yahoo address and an app password (the page explains how to
create one). After you connect, the client receives its tokens and
the mail tools appear.