A self-hosted DMARC report viewer and email authentication dashboard. Connects to your IMAP mailbox, parses aggregate reports, and gives you a clear picture of your domain's email authentication health.
- IMAP ingestion — connects to any IMAP mailbox, pulls DMARC (RUA) and TLS-RPT attachments (
.xml,.xml.gz,.zip,.json,.json.gz) - Report parsing — RFC 7489 DMARC aggregate reports and RFC 8460 TLS-RPT reports, fully parsed and stored
- Dashboard — pass rates, timelines, top senders, domain overview
- DNS health checks — MX, DMARC, SPF, DKIM, TLSA/DANE, MTA-STS, and TLS Reporting records with warnings and recommendations
- Detected domains — domains from your reports appear on the DNS page for one-click health checks
- Background fetch — automatic IMAP polling on a configurable interval (default: every 6 hours)
- Encryption at rest — IMAP passwords encrypted with Fernet
- Single-container deploy — one Docker image, bundled frontend, auto-runs migrations on startup
This is the recommended way to run Sigil. No need to clone the repo.
# 1. Download the compose file and example env
curl -LO https://raw.githubusercontent.com/Paul1404/Sigil/main/docker-compose.yml
curl -LO https://raw.githubusercontent.com/Paul1404/Sigil/main/.env.example
# 2. Create your .env and fill in the values
cp .env.example .env
# 3. Generate required secrets
python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# 4. Start everything
docker compose up -dOpen http://localhost:8000 and log in with the ADMIN_PASSWORD you set in .env.
docker compose pull
docker compose up -dMigrations run automatically on container start.
All configuration is through environment variables. See .env.example for the full list.
| Variable | Required | Description |
|---|---|---|
POSTGRES_PASSWORD |
Yes | Password for the bundled PostgreSQL container |
ENCRYPTION_KEY |
Yes | Fernet key for encrypting IMAP passwords at rest |
ADMIN_PASSWORD |
Yes | Password to log into the dashboard |
SECRET_KEY |
Yes | Signs JWT tokens — use a random string |
FETCH_INTERVAL_HOURS |
No | Hours between automatic IMAP fetches (default: 6) |
SIGIL_PORT |
No | Host port to expose (default: 8000) |
CORS_ORIGINS |
No | Comma-separated allowed origins. Leave empty for same-origin |
DATABASE_URL |
No | Override to use an external PostgreSQL instead of the bundled one. Must use postgresql+asyncpg:// scheme |
If you already run PostgreSQL, set DATABASE_URL in your .env and remove the sigil-db service from docker-compose.yml:
DATABASE_URL=postgresql+asyncpg://user:password@your-db-host:5432/sigilSigil runs on port 8000 by default. Put it behind your existing reverse proxy (nginx, Caddy, Traefik, etc.) and set CORS_ORIGINS to your public URL:
CORS_ORIGINS=https://sigil.example.comAfter logging in, go to Settings and add your IMAP mailbox. Sigil will scan for DMARC and TLS-RPT report emails. You can trigger a manual fetch or wait for the next scheduled run.
Most DMARC report providers (Google, Microsoft, Yahoo, etc.) send reports as email attachments to the rua address in your DMARC record. Point that to a mailbox Sigil can read.
If you prefer to build locally instead of pulling from ghcr.io:
git clone https://github.com/Paul1404/Sigil.git && cd Sigil
docker compose up -d --buildOr for development without Docker:
# Backend (Python 3.12+)
cd backend
pip install -r requirements.txt
alembic upgrade head
uvicorn main:app --reload
# Frontend (Node 20+)
cd frontend
npm install
npm run devThe frontend dev server proxies /api to localhost:8000.
GET /api/health Health check
GET /api/dashboard/stats Aggregate stats
GET /api/dashboard/timeline Pass/fail over time
GET /api/reports List DMARC reports (filterable by domain, date)
GET /api/reports/{id} Single report with records
GET /api/tls-reports List TLS-RPT reports
GET /api/tls-reports/summary TLS report summary by domain
POST /api/dns/check Run DNS health checks for a domain
GET /api/dns/domains Domains detected from ingested reports
GET /api/mailboxes List configured mailboxes
POST /api/mailboxes Add a mailbox
PUT /api/mailboxes/{id} Update a mailbox
DELETE /api/mailboxes/{id} Delete a mailbox
POST /api/mailboxes/{id}/fetch Trigger manual fetch
GET /api/inbox Non-report emails
backend/
main.py FastAPI app, all routes
models.py SQLAlchemy models
schemas.py Pydantic request/response schemas
dns_checker.py MX, DMARC, SPF, DKIM, TLSA, MTA-STS, TLSRPT checks
imap_fetcher.py IMAP connection + email processing
dmarc_parser.py RFC 7489 XML report parser
tls_parser.py RFC 8460 TLS-RPT JSON parser
scheduler.py Background fetch jobs (APScheduler)
database.py Async DB engine + sessions
config.py Settings from env vars
encryption.py Fernet encrypt/decrypt for IMAP passwords
auth.py JWT auth + password verification
alembic/ Database migrations
frontend/
src/
pages/ Dashboard, Reports, DNS, Settings, Inbox
components/ Shared UI components
api.js API client
- Backend: FastAPI, SQLAlchemy (async), Alembic, PostgreSQL, dnspython, APScheduler
- Frontend: React 19, Vite, Tailwind CSS v4, Recharts
- Container: Multi-stage Docker build (Node + Python)
MIT