Install

Quickstart

Run the container or the binary behind HTTPS, with a master key and storage.

What every deployment needs

  1. 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. Set POSTKEEP_PUBLIC_URL to the origin only, such as https://mail.example.com, with no path.

  2. 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:

    sh
    docker run --rm postkeep/postkeep generate-key
    # or: postkeep generate-key, or: openssl rand -hex 32

    Pass it as POSTKEEP_MASTER_KEY, or put it in a file and set POSTKEEP_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).

  3. Persistent storage. By default the server uses a SQLite file (/data/postkeep.db in the image), so mount a volume at /data. Upgrading from 0.2.x with the default SQLite path: 0.3.0 looks for postkeep.db, so rename your existing database file to postkeep.db (in the image, /data/postkeep.db) or point POSTKEEP_DATABASE_URL at it before starting. Account-page users sign in again once. If 0.3.0 has already started and created an empty postkeep.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=require encrypts without that check. If the provider uses a private CA, also add sslrootcert=/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 set POSTKEEP_DATABASE_IDLE_TIMEOUT=300 and POSTKEEP_DATABASE_MAX_LIFETIME=600. These are examples, not defaults. Migrations run at start. Behind a transaction pooler, run them on a direct connection instead: set POSTKEEP_DATABASE_MIGRATE_URL to it, run postkeep migrate as a release command (it exits 0 when there is nothing to do), and set POSTKEEP_DATABASE_MIGRATE_ON_START=false so 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/postkeep

The 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/mcp

The 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.