Sign inSign up

christophmotal/dmarc-parser

By christophmotal

•Updated 4 months ago

Self-hosted DMARC + SMTP-TLS-RPT report viewer. Pulls from IMAP, Microsoft 365 or drop folder.

Image
Security
Monitoring & observability
1

1.1K

christophmotal/dmarc-parser repository overview

⁠DMARC Parser

A self-hosted analyser for DMARC aggregate reports (RFC 7489) and SMTP TLS reports (RFC 8460). Pull reports from one or more mailboxes, parse the XML / JSON payloads, store them in SQLite and inspect the results in a MudBlazor UI — without sending data to a third party.

⁠Features

  • DMARC aggregate reports — XML, gzip, zip; per-record DKIM/SPF alignment, disposition, source-IP rDNS lookup
  • SMTP TLS reports (TLS-RPT) — JSON / gzip per RFC 8460; per-policy success/failure session counts and failure-detail breakdown
  • Three ingestion sources — drop folder, classic IMAP (basic auth), or Microsoft 365 mailbox via Graph API (Azure-AD client-credentials, no IMAP enablement needed)
  • Built-in mailbox self-test for both IMAP and M365 sources (round-trip Create → Search → Fetch → Move → Verify)
  • Manual upload for ad-hoc inspection of single report files
  • Dashboard with KPIs, pass-rate timeline, disposition split and top reporters
  • Reverse-proxy friendly — HTTP only on port 18080, terminate TLS upstream
  • Auto-migration — SQLite schema is applied on first start

⁠Quick start

docker run -d \
  --name dmarc-parser \
  -p 18080:18080 \
  -v "$(pwd)/data:/app/data" \
  --restart unless-stopped \
  christophmotal/dmarc-parser:latest

…or with docker-compose:

services:
  dmarc-parser:
    image: christophmotal/dmarc-parser:latest
    container_name: dmarc-parser
    ports:
      - "18080:18080"
    volumes:
      - ./data:/app/data
    restart: unless-stopped

Open http://localhost:18080/⁠, configure a mail source under Mail Sources, run the self-test, enable polling.

⁠Volume layout

Everything writeable lives under /app/data:

PathPurpose
/app/data/db/SQLite database (dmarc.db) — reports, policies, config
/app/data/drop/Drop folder source: place report files here, get auto-ingested. Sub-folders processed/, error/, unsupported/ are created automatically
/app/data/logs/NLog file targets

The IMAP / M365 secrets in the database are encrypted with the ASP.NET Core Data Protection API, whose keys are persisted in the same SQLite database — back up dmarc.db to back up everything.

⁠Configuration

Defaults work out of the box. To override settings, mount an appsettings.Production.json next to the container's working directory or pass standard ASP.NET Core environment variables:

environment:
  ConnectionStrings__Default: "Data Source=data/db/dmarc.db"
  FolderMailSource__DirectoryPath: "data/drop"
  Logging__LogLevel__Default: "Information"

The polling background service ticks every 60 seconds; per-source poll intervals are configured in the UI (default 60 minutes).

⁠Ports

  • 18080/tcp — HTTP. The image does not terminate TLS — front it with a reverse proxy (Caddy, Traefik, nginx, IIS) for HTTPS.

⁠Image

  • Platform: linux/amd64
  • Base: mcr.microsoft.com/dotnet/aspnet:10.0
  • Runs as: root by default for bind-mount ergonomics. Override with user: "1654:1654" in compose plus chown of the host data directory if you want non-root.

⁠Tags

  • latest — most recent release

⁠Architecture

Layered .NET solution: Core (entities + interfaces) → Application (services, parsers, ingestion) → Infrastructure (EF Core / MailKit / Microsoft Graph) → Web (Blazor Server). SQLite is single-file, no external DB dependency.

⁠License

MIT — Copyright (c) 2026 Christoph Motal. See the LICENSE file in the source repository.

Tag summary

Content type

Image

Digest

sha256:e2991262f…

Size

133.4 MB

Last updated

4 months ago

docker pull christophmotal/dmarc-parser