72 lines
2.9 KiB
Markdown
72 lines
2.9 KiB
Markdown
# dmarc-to-discord
|
|
|
|
A tiny HTTP relay that turns [parsedmarc](https://github.com/domainaware/parsedmarc) aggregate-report webhooks into nicely formatted Discord embeds.
|
|
|
|
parsedmarc parses DMARC aggregate reports from your inbox and POSTs each one as JSON to a webhook URL of your choosing. This service is that webhook: it listens for parsedmarc's POSTs, builds one metadata embed plus one embed per record (source IP, alignment, disposition, auth results, override reasons), and forwards them to a Discord channel.
|
|
|
|
## How it looks
|
|
|
|
Each report produces:
|
|
|
|
- **1 metadata embed** — reporter, report ID, timespan, published policy (`p`, `sp`, `adkim`, `aspf`, `pct`, `fo`), and a pass/total summary.
|
|
- **1 embed per record** — source IP/country/rDNS/ASN, message count, disposition, header-from, DMARC/SPF/DKIM alignment, policy-evaluated SPF/DKIM, raw auth results, and any policy override reasons.
|
|
|
|
Embeds are colored green (DMARC aligned), red (quarantine/reject), or orange (anything else). Discord allows max 10 embeds per message, so larger reports are split across multiple messages.
|
|
|
|
## Configuration
|
|
|
|
Environment variables:
|
|
|
|
| Variable | Default | Description |
|
|
| --- | --- | --- |
|
|
| `DISCORD_WEBHOOK_URL` | *(required)* | Discord channel webhook URL |
|
|
| `LISTEN_HOST` | `127.0.0.1` | bind address |
|
|
| `LISTEN_PORT` | `8080` | bind port |
|
|
|
|
## Running
|
|
|
|
This project uses [uv](https://docs.astral.sh/uv/) for Python and dependency management.
|
|
|
|
```sh
|
|
uv run dmarc-to-discord
|
|
# or, for local hacking:
|
|
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... uv run dmarc-to-discord
|
|
```
|
|
|
|
`GET /`, `/health`, and `/healthz` return `200 ok` for liveness checks.
|
|
|
|
## Wiring up parsedmarc
|
|
|
|
In `parsedmarc.ini`:
|
|
|
|
```ini
|
|
[webhook]
|
|
aggregate_url = http://127.0.0.1:8080/
|
|
```
|
|
|
|
(parsedmarc also supports `forensic_url` and `smtp_tls_url`; this relay currently only handles the aggregate-report schema.)
|
|
|
|
## Running with Docker
|
|
|
|
The included `Dockerfile` builds the service with uv. The image:
|
|
|
|
- exposes port `8080` and binds to `0.0.0.0` inside the container (override with `LISTEN_PORT` / `LISTEN_HOST`);
|
|
- requires the `DISCORD_WEBHOOK_URL` environment variable;
|
|
- runs as an unprivileged user;
|
|
- serves `/healthz` (returns `200 ok`) for container health checks.
|
|
|
|
```sh
|
|
docker build -t dmarc-to-discord .
|
|
docker run -p 8080:8080 -e DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/... dmarc-to-discord
|
|
```
|
|
|
|
Any platform that builds from a Dockerfile can deploy it: point it at this
|
|
repository, set `DISCORD_WEBHOOK_URL`, expose port `8080`, and use `/healthz`
|
|
as the health check.
|
|
|
|
## Notes
|
|
|
|
- The server speaks plain HTTP. Terminate TLS in front of it, or keep it on a private network with parsedmarc.
|
|
- Discord 429s are honored via `retry_after`; there's a 0.5 s gap between messages to stay friendly to the rate limiter.
|
|
- No persistence — if Discord is down when a report arrives, the report is dropped (parsedmarc will not retry).
|