self-hosted / docker / fastapi

Search every delivery.
Watch every bounce.

Self-hosted Postfix log search correlated by queue ID, plus a delivery-health dashboard built from your own mail logs.

Two surfaces over the same logs.

One tool for the two ways mail-ops actually works: the fast lookup when something breaks, and the quiet watch on whether delivery is healthy.

02

Delivery-health dashboard

A glanceable read on aggregate delivery health over time. A background scanner rolls log data into hourly, daily, and weekly tiers in a libSQL store, so trends stay fast across months of mail.

  • Volume, bounce / defer rate, SLA
  • Per-domain mix and slow domains
  • DSN breakdown and failure categories
  • TLS coverage and DKIM signing rate

Everything is a log line. So is the answer.

No agents, no log shipping, no external store. It reads the mail.log the box already writes and turns it into search and signal.

Search
  • Recipient, domain, or subject queries
  • Date-range filtering
  • Server-Sent Events progress
  • Status filter chips + detail panel
  • CSV / JSON export, copy to clipboard
  • Email a report with CSV attached
Observability
  • Bounce / defer rate and SLA
  • Per-domain mix + slow domains
  • DSN + failure-category breakdown
  • TLS coverage by negotiated version
  • DKIM signing rate and reasons
  • Prometheus metrics at /metrics
  • Bundled Grafana dashboards
Operations
  • Local or SSHFS-mounted remote logs
  • Rotation + gzip aware discovery
  • Background scanner with resume
  • Hourly to daily to weekly rollups
  • libSQL (sqld) store + retention
  • Docker: 4 workers + sqld sidecar
  • /health liveness probe

Is delivery healthy right now?

The signal that matters, readable in seconds. The same six KPIs and trend charts you get at /stats, rolled up hourly to weekly so months of mail stay fast.

Delivery Health Last 24 hours
representative sample data
Sent 98,204 across 412 domains
Bounced 1,673 +4% vs prior 24h
Deferred 906 Mostly transient retries
Bounce Rate 1.7% Within normal range
Delivery SLA 99.4% Delivered under 5 minutes
Daily Volume · Past Year Rolled up hourly to daily to weekly, so a year of mail stays fast
Volume Over Time Sent, deferred, bounced, and expired per interval (UTC)
sent deferred bounced expired
Domain Diagnosis Top domains by volume
acme.io 12,901
globex.co 8,440
initech.dev 5,210
slow.net 1,204
ghost.mail 88
Failure Rate Trend Bounce & defer rate · final partial period shaded
bounce rate defer rate
TLS Coverage
TLS 1.3 78%TLS 1.2 20%none 2%
DKIM Signing
98.6%
signed
Bounce & Defer Reason Codes Top RFC 3463 enhanced status codes
5.1.1 Bad destination mailbox 612
4.2.2 Mailbox full 388
5.7.1 Delivery not authorized 274
4.4.1 No answer from host 190
5.7.26 Multiple auth checks failed 121
4.7.0 Greylisted, retry later 96
Domain Risk Matrix Volume against failure rate · top-left is risk
failure rate ↑volume →

Or bring your own stack.

Scrape /metrics with Prometheus (durable counters survive restarts and aggregate across workers), drop in the bundled Grafana dashboards over the Infinity datasource, and point uptime checks at /health. Pull the same numbers over HTTP from the stats CLI or a scoped read-only key, and let an embedded MCP server expose search and stats to your agents.

endpoints GET /stats GET /metrics GET /health POST /mcp
integrate Grafana stats CLI STATS_API_KEY MCP server

It tells you before you have to look.

Search is for when you already know something broke. Everything else, the tool watches for you, then puts a readable summary where you will actually see it.

Threshold & anomaly alerts

Set a threshold or let it learn the baseline. Scope to the domains that matter. Route to email or a webhook.

Scheduled digests

A branded HTML delivery-health digest in your inbox, on your schedule.

Reports & export

An LLM-written summary from current and prior stats, plus one-click export of the live dashboard.

Pick the surface. Keep the signal.

Twelve prebuilt themes, chosen for mail-ops eyes and long shifts. The accent, temperature, and contrast change. Delivered green, bounced red, deferred amber stay fixed in every one.

delivery health
acme.io12,901 sent
Search
Midnight Ops default
delivery health
acme.io12,901 sent
Search
Graphite Blue quiet enterprise
delivery health
acme.io12,901 sent
Search
Terminal Green log + search
delivery health
acme.io12,901 sent
Search
Slate Amber warmer ops
delivery health
acme.io12,901 sent
Search
Carbon Violet modern product
delivery health
acme.io12,901 sent
Search
Steel Mono neutral noc
delivery health
acme.io12,901 sent
Search
Nord Frost low strain
delivery health
acme.io12,901 sent
Search
Tidewater deep teal
delivery health
acme.io12,901 sent
Search
Synthwave showcase
delivery health
acme.io12,901 sent
Search
Obsidian oled black
delivery health
acme.io12,901 sent
Search
Paper Console light
delivery health
acme.io12,901 sent
Search
Sandstone warm light

Up in four commands.

No source checkout. Pull the compose file and config template, set one secret, and start the app container with its sqld sidecar. It runs on the box that already collects the mail.

  • App + sqld over a private Docker network
  • Search at /, dashboard at /stats
  • Pin :v3.1.1 for reproducible deploys
Full install guide →
bash
$ mkdir postfix-insights && cd postfix-insights# a working dir$ curl -fsSL https://raw.githubusercontent.com/Xodus-CO/postfix-insights/main/docker-compose.prod.yml -o docker-compose.yml# compose file$ curl -fsSL https://raw.githubusercontent.com/Xodus-CO/postfix-insights/main/.env.example -o .env# config template$ sed -i "s/^CSRF_SECRET=$/CSRF_SECRET=$(openssl rand -hex 32)/" .env# set the secret$ docker compose up -d# go→ http://<host>:8080