- Python 97.5%
- Dockerfile 2.5%
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| Dockerfile | ||
| README.md | ||
| snds_to_slack.py | ||
snds-to-slack
Pulls the Microsoft Smart Network Data Services daily data export and posts a digest to Slack.
The container runs once and exits — scheduling belongs to cron, a systemd timer, or a k8s CronJob.
Message
One message per run, one line per IP:
SNDS report 2026-07-28
:large_yellow_circle: zoo 168.119.192.202 YELLOW (3102,2204,2201,0.1)
:red_circle: smukfest 168.119.192.207 RED (6014,2261,2944,0.1)
The name before the IP is the first label of its PTR record
(frieda.hetzner.venuemanager.net → frieda), falling back to the IP if no PTR resolves.
The tuple is (RCPT commands, DATA commands, message recipients, complaint rate).
Complaint rate < 0.1% is reported as 0.1.
Routing
The complete message always goes to SLACK_CHANNEL_GREEN. If any IP in the export is
YELLOW, RED, or an unrecognised status, the same complete message also goes to
SLACK_CHANNEL_RED. If both variables name the same channel, it is posted once.
Configuration
Copy .env.example to .env and fill it in:
| Variable | Required | Purpose |
|---|---|---|
SNDS_KEY |
yes | Automated Data Access key from the SNDS portal |
SLACK_WEBHOOK_URI |
yes | Incoming webhook URL |
SLACK_CHANNEL_GREEN |
yes | Channel that receives every report |
SLACK_CHANNEL_RED |
yes | Channel that additionally receives non-GREEN reports |
SLACK_NAME |
no | Bot display name, defaults to SNDS |
The channel and username overrides in the payload only take effect on a legacy
Incoming Webhook. A webhook created through a modern Slack app is bound to one channel and
will ignore both — in that case use two webhooks or a legacy one.
Environment variables take precedence over .env, so docker run --env-file works either way.
Running
docker build -t snds-to-slack .
# print the message and target channels, post nothing
docker run --rm --env-file .env snds-to-slack --dry-run
# post for real
docker run --rm --env-file .env snds-to-slack
Without Docker: python3 snds_to_slack.py --dry-run (Python 3.9+, no dependencies).
Scheduling
The SNDS reporting window closes at 09:00 UTC, so run shortly after:
5 10 * * * docker run --rm --env-file /home/rune/development/snds-to-slack/.env snds-to-slack
Exit codes
| Code | Meaning |
|---|---|
0 |
Posted, or the export was empty (nothing is posted on an empty export) |
1 |
Could not fetch SNDS data, or a Slack post failed |
2 |
Missing required configuration |
As of 2026 SNDS Automated Data Access keys expire after roughly 30 days. A sudden run of
exit-code-1 failures usually means an expired SNDS_KEY rather than an outage — regenerate
it in the SNDS portal.
Testing
SNDS_TEST_FILE=/path/to/sample.csv reads the export from a local file instead of the
network, which makes the all-GREEN and malformed-row paths testable without live data.