Apprise-compatible HTTP → Resend API email bridge for changedetection.io
1.8K
Bridge microservice that receives notifications from changedetection.io
through an Apprise-compatible (json://) endpoint and forwards them via the
Resend API.
Resend API credentials stay confined to the Docker container and are never exposed to changedetection. The bridge authentication token can be revoked at any time without touching the Resend account.
notify-bridge/
├── app.py # Flask app (endpoint + Resend API call)
├── Dockerfile
├── requirements.txt
├── docker-compose.snippet.yml # Block to add to your compose file
├── tests/
│ └── test_token_validation.py
├── README.md
└── README-IT.md
re_xxxxxxxxxxxx)MAIL_FROM address must use the domain verified in Resend
(for example [email protected])python3 -c "import secrets; print(secrets.token_urlsafe(32))"
Use a token made only of URL-safe characters. Avoid /, +, =, spaces,
and quotes. The command above already generates a safe token.
You can also use this preconfigured generator:
tools.gioxx.org password generator.
.env file (never commit it)BRIDGE_TOKEN=the_token_generated_above
BRIDGE_PORT=5001 # optional, change only if 5001 is already in use
RESEND_API_KEY=re_xxxxxxxxxxxxxxxxxxxx
[email protected]
MAIL_FROM_NAME=ChangeDetection
[email protected]
If you set a custom token manually, keep it URL-safe. Stick to letters,
numbers, _, and -.
For multiple recipients: [email protected],[email protected]
Copy the contents of docker-compose.snippet.yml into the services:
section of your existing docker-compose.yml, then handle networking based on
your setup:
Case A - no explicit networks: block in the compose file:
Docker Compose automatically connects all services to the default network.
Do not add anything: notify-bridge and changedetection can already see each
other by name. Remove or comment out the networks: block in the snippet.
Case B - an explicit network is already declared (for example changedetection_net):
Uncomment the networks: block in the snippet and use the name of the network
already present in your compose file. Do not redeclare the global networks:
block; it is already there.
Port note: changedetection.io uses port 5000 internally. notify-bridge uses 5001 by default, so there is no conflict. Both ports stay inside the Docker network and are not exposed on the host. If 5001 is also in use, just set
BRIDGE_PORTin.envto a different value.
docker compose up -d --build notify-bridge
docker compose exec notify-bridge wget -qO- http://localhost:5001/health
# → {"status":"ok"}
Go to Settings → Notifications and add the Apprise URL:
json://notify-bridge:5001/YOUR_TOKEN
notify-bridge -> Docker service name, resolved internally5001 -> internal bridge port, not exposed on the hostYOUR_TOKEN -> value of BRIDGE_TOKEN in .envIf you changed BRIDGE_PORT, update the number in the URL accordingly.
# 1. Generate a new token
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# 2. Update BRIDGE_TOKEN in .env
# 3. Restart only the bridge
docker compose up -d notify-bridge
# 4. Update the URL in changedetection
The Resend API key is never touched.
Go to resend.com -> API Keys -> revoke the key, generate a new one, update
RESEND_API_KEY in .env, and restart the container. The bridge token does
not change.
| Variable | Default | Notes |
|---|---|---|
BRIDGE_TOKEN | required | Bridge authentication token |
BRIDGE_PORT | 5001 | Internal container port, not exposed on the host |
RESEND_API_KEY | required | Resend API key (re_...) |
MAIL_FROM | required | Sender, verified domain on Resend |
MAIL_FROM_NAME | ChangeDetection | Display name in the "From:" field |
MAIL_TO | required | Recipients, separated by commas |
Run the local checks with:
python -m unittest discover -s tests -v
python -m py_compile app.py tests/test_token_validation.py
GitHub Actions also runs these checks on pull requests and pushes to main.
Content type
Image
Digest
sha256:b90a45437…
Size
48.4 MB
Last updated
4 months ago
docker pull gfsolone/notify-bridge