- Python 99.7%
- Shell 0.3%
Since core 2.61 the SMTP relay is no longer chosen via configured_addr: the core tries the newest relay first and falls back to the next one if a relay is unreachable. The MSG_FAILED failover handler and resilient send patch switched configured_addr and resent, which no longer changes the relay and only produced delayed duplicate resends. - remove on_msg_failed failover and _setup_resilient_mode - /setprimary and /resilient reply with a deprecation note - /transports lists relays in the core's sending order - require deltachat-rpc-server>=2.62.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| .pi | ||
| static | ||
| tests | ||
| web | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| activitypub.py | ||
| background-light.jpg | ||
| background-light.png | ||
| background.jpg | ||
| bot.py | ||
| Caddyfile | ||
| CHANGELOG.md | ||
| channels.py | ||
| cmping.py | ||
| cmping_commands.py | ||
| commands.py | ||
| config.py | ||
| CONTEXT.md | ||
| database.py | ||
| dc_helpers.py | ||
| docker-compose.yml | ||
| Dockerfile | ||
| formatting.py | ||
| handlers.py | ||
| icon.png | ||
| moderation.py | ||
| README.md | ||
| requirements.txt | ||
| security.py | ||
| set_admin.py | ||
| state.py | ||
| sticker_tool.py | ||
| stickers.py | ||
| transports.py | ||
| update.sh | ||
| virustotal.py | ||
Delta Chat Bouncer Bot
Delta Chat bot designed to maintain group quality by monitoring inactivity and save server resouces by not sending mails to stale users. It scans group members and reports users who haven't been seen online for over 21 days.
Features
- ⚠️ Inactivity Reports (
/bounce): In groups with/autokickenabled, displays members approaching the auto-kick threshold (< 7 days or < 1 day remaining) as well as observation progress for silent members still in their grace period. In other groups, reports members inactive for over 21 days. Displays user role badges (👑Admin,⭐Autokick Ignored,💤Away) and member age indicators (colored circles🔴..⚪or squares🟥..⬜for multi-group members). Operates on an independent 60s cooldown. - 🧹 Automatic Inactivity Kick with Warnings (
/autokick): Automatically purge stale, inactive members from group chats in the background. Features a two-stage warning system: sends a private 1-on-1 direct message warning to inactive candidates and broadcasts a daily summary to the group (once every 24h). Members are kicked only after receiving a warning and passing a 24-hour grace period. Supports cryptographic fingerprint exemptions (/autokick ignore) and/awayvacation status exemptions. - 🛡️ Auto-kick Fingerprint Ignore List (
/autokick ignore): Exempt specific members or service bots from auto-kick by resolving and storing their cryptographic key fingerprint. - 👞 Manual Member Kick (
/kick <userid>): Remove a specific member or multiple members from a group chat by contact ID (e.g./kick 123or/kick /contact123), search query, or by replying to their message. - 💤 Away Status & Auto-Reply (
/away,/back): Set a temporary away message (e.g./away on vacation until Monday). When other members mention you by name in group chats, the bot informs them privately of your away status. Bare/awaydisplays your current status or usage instructions. Running/backclears away status and notifies users who messaged you. - 📖 Group Chat Catalog (
/chats): Users can browse all group chats cataloged by the bot, complete with name, description, and real-time membership count. - 📢 Delta Chat Channels Catalog (
/dchannels): Users can browse all channels cataloged by the bot, complete with name and description. - 🌐 Channel Web Preview & RSS Feeds (
/c/{token}): Public web previews for registered channels with live message history, attachments, accessible QR code join modals (with Tab focus trapping, Escape key support, focus restoration, and ARIA dialog attributes), inline ✓ Copy Link feedback (no blocking alerts), OpenGraph/Twitter Card metadata, zero-repaint background rendering, Light / Dark / System theme switcher with instant zero-transition toggling andlocalStoragepersistence, and standard RSS 2.0 feeds (/c/{token}/rss.xml) featuring per-post permalinks (#post-{msg_id}), exact media enclosure byte sizes, and CDATA breakout escaping. Soft-delete tombstone handling ensures graceful messaging when channels are removed from the catalog. - 🪐 Fediverse / ActivityPub Federation (
@<token>@domain): Every registered channel acts as a full Fediverse actor (type: "Service"/ 🤖 Bot). Users on Mastodon, Pleroma, Misskey, etc., can search@<token>@<domain>via WebFinger (RFC 7033), follow channels, and receive new messages and media attachments in their home feeds via authenticated HTTP Signatures (RFC 9421&draft-cavage-http-signatures) with strict KeyId/Actor origin binding, signing key ownership verification (keyowner/publicKeycross-check), 300s anti-replay protection, foreign inbox delivery protection, and bounded backfill concurrency. - 🔐 Join Approval Workflows: Supports public and private groups. Requests to join public groups immediately receive an invite link, while private groups (
🔐) require approvals from existing members in the group via dynamic/approve<ID>commands. - 👋🏻 Custom Welcome Messages (
/welcome): Configure customizable welcoming greetings for new members joining the group with custom rules text and visual age badges. - 🔗 Invite Link (
/invite): Generate a SecureJoin invite link and QR code image for the current group chat. Available to all users with an independent 1-minute cooldown (admins are exempt). For private group chats, the generated link is single-use and will be automatically deleted from the chat once a new member joins. - 🔍 Member Search (
/search [email1] ...): Find group members by one or more email terms (case-insensitive substring matching) or by replying to a message containing email addresses. Displays user role badges (👑,⭐,💤), multi-chat indicators (🟥..⬜), and searches across all active transports (both primary and secondary addresses). - 📬 Relay Check (
/relays): Scan for group members using public Russian mail providers (Yandex, Mail.ru, etc.). - 🏆 Activity Ranking (
/top): Show the 10 most active members in the last 24 hours (independent 60s cooldown). - 🏓 ChatMail Ping (
/cmping): Ping mail relays (transports) to/from specified target servers using thecmpingutility. Features real-time reaction-based progress tracking (⏳,☑️,❌) and runs asynchronously. - 📡 Server Connectivity Monitoring: Automatic periodic monitoring of server connectivity using a round-robin algorithm. Employs an incident-based alerting system with in-place dynamic message editing (
🚨 Ongoing→⚠️ Ongoing (Partial Recovery)→✅ Resolved) to prevent notification noise, along with accurate root-cause fault isolation. Configurable interval viaCMPING_MONITOR_INTERVALenv var (default: 30 min). - 👤 Contact Sharing: Reports include
/contact<ID>links to quickly share a contact card for any user. - 🔄 Multiple Mail Relays: Supports multiple mail servers. Relay selection and failover are handled by the Delta Chat core (2.61+), which sends via the newest relay first and falls back to the next one if a relay is unreachable.
- ⏳ 21-Day Grace Period: The bot tracks group activity in the background and requires 21 days of observation before reporting "never seen" users.
- 🛡️ Secure Administration & Rate Limiting: Claim ownership with
/initadmin. Admins bypass rate limits and have exclusive control over bot settings. All public web endpoints are rate-limited per client IP (with trusted reverse-proxy X-Forwarded-For extraction), returning HTTP 429 on excess. QR code cache is bounded at 200 entries (FIFO eviction). - 📱 QR Code Link: Generates a SecureJoin QR code in the logs for easy device linking.
- 📋 Startup Version Check: Automatically checks and logs versions of Bouncer Bot, DeltaChat Core, RPC Client,
deltabot-cli, andcmpingat startup. - 🦠 VirusTotal Inspection (
/virus): Inspect links or attached files for malware, phishing, and security threats using the VirusTotal API v3. Supports direct URL scans (/virus <url>), replies to messages containing links, or replies to messages with attached files. Employs a global FIFO queue and rate limiter (1 check every 15 seconds) to strictly adhere to VirusTotal free tier limits, with live in-place message updates as scans complete. - 🎨 Sticker Creation (
/sticker,/stickernobg): Convert any image into a standard WebP sticker compatible with Delta Chat, Telegram, and Signal with proportional 512px dimension scaling and automatic EXIF orientation transpose. Triggered either by replying to an image with/stickeror/stickernobg, or by sending an image with the command in its caption./stickerpreserves the original image and background (5s cooldown), while/stickernobg(or/sticker nobg) usesrembgwith the lightweightu2netpmodel (only 4.7 MB) and a 15s cooldown with a global concurrency lock. Images are automatically pre-scaled down to 512px before AI segmentation to minimize CPU and memory usage, and background removal runs in an isolated subprocess (sticker_tool.py) with disabled memory arenas, ensuring 100% of memory is immediately reclaimed by the OS and the main bot daemon remains at ~75–80 MB. Background removal can be disabled viaENABLE_REMBG=falseor configured with other models viaREMBG_MODEL. Downloaded models are cached persistently in./data/u2netso they are never re-downloaded across restarts or updates. - ⚡ High-Performance Architecture & Read Pool: Optimized SQLite read connection pool (
_ReaderConnectionPool) supporting concurrent non-blocking reads in WAL mode, eliminating N+1 connection overhead and reducing latency by >12x. Intensive I/O and media processing (VirusTotal inspection, channel post media ingestion, Pillow WebP image optimization, and QR code generation) are fully offloaded to asynchronous background worker threads (asyncio.to_threadand dedicated daemon workers), keeping the Delta Chat event loop completely non-blocking. - 🐳 Docker Ready: Easy deployment using Docker Compose.
Setup
-
Clone the repository:
git clone https://git.gluek.info/gluek/deltachat_bouncer cd deltachat_bouncer -
Initialize Account: Run the initialization command once to set up the bot's email and password:
docker compose run --rm bot python bot.py init bot-email@example.com your_password -
Start the Bot:
docker compose up -d docker compose logs -fNote: If it's a new account, a QR code will be printed to the logs for linking your Delta Chat device.
-
Claim Admin Ownership: Send
/initadminto the bot in a private message to become the administrator.
Commands
/bounce [username]— Show user activity, or check inactive members in current group (Shows warning candidates and observation progress if/autokickis on, otherwise 21 days; displays role badges and age indicators)./search [email1] ...— Search for group members by one or more emails (case-insensitive substring match) or by replying to a message containing email addresses./away [message]— Set away status or view current away status without clearing it./back— Clear away status and notify users who messaged you while you were away./relays— Find group members using public Russian mail providers./top— Show the 10 most active members in the last 24 hours./invite— Generate an invite link and QR code for this group./chats— Show the catalog of registered group chats available to join./chat<ID> [message]— Request an invite link to the group (Private chat only)./dchannels— Show the catalog of registered Delta Chat channels with invite links and web preview URLs./dchannel<ID>— Request the invite link and web preview URL for a channel./cmping <server1> ...— Ping mail relays to/from specified target servers (15s cooldown, domain-validated)./virus <url>— Scan a URL, or reply to a message containing a link or attached file with/virusto inspect with VirusTotal (15s global rate limit)./sticker— Convert replied or attached image to a WebP sticker (preserves original image/background; 5s cooldown)./stickernobg— Convert replied or attached image to a WebP sticker with background removed (15s cooldown, serialized)./slap [username]— Slap a user with a large trout (or reply to a message; 15s cooldown)./approve<ID>— Approve a pending join request for a private group (Group chat only)./decline<ID> [reason]— Decline a pending join request for a private group with an optional reason (Group chat only)./contact<ID>— Share contact card for the given ID (e.g.,/contact123)./help— Show available commands and bot information./donate— Support project development ❤️/initadmin— Claim administrative ownership (private chat only)./autokick [on/off/days/ignore/unignore]— Configure auto-kick with warnings (default: 90 days, e.g./autokick 30) or manage cryptographic fingerprint ignore list (/autokick ignore <email/nick>,/autokick unignore <fp/email>) (Admin only)./kick <user_id>— Remove a member from the current group by contact ID, search query, or message reply (Admin only)./chatadd [description]— Add the current group chat to the catalog (Admin only). Falls back to group description if not provided./chatremove— Remove the current group chat from the catalog (Admin only)./chatdesc<ID> <text>— Update description of cataloged group chat (Admin only)./dchanneladd <URL>— Join and add a channel to the catalog as unlisted by default (Admin only)./dchannelremove [ID]— Remove a channel from the catalog (Admin only). If the channel author removes the bot from the channel, it is also automatically removed from the catalog./dchanneldesc<ID> <text>— Update description of cataloged channel (Admin only)./dchannelpub<ID>on//dchannelpub<ID>off— Toggle channel public catalog visibility (Admin only). Unlisted channels are hidden from the public catalog and landing page, but maintain active web preview URLs and RSS feeds./url [base_url]— Show or set the base web URL used for public channel previews and RSS feeds (Admin only)./private <on/off>— Toggle cataloged chat privacy status (Admin only)./welcome [on/off/on <text>]— Configure welcome messages for new members (Admin only)./transports— Show configured mail relays & stats (Admin only)./addtransport— Add a backup mail relay (Admin only, private 1-on-1 chat only for credential security)./rmtransport <addr>— Remove a mail relay (Admin only)./cmpingadd <server>— Add a server to connectivity monitoring rotation (Admin only)./cmpingdel <server>— Remove a server from monitoring (Admin only)./cmpinglist— Show all monitored servers, pair count, and rotation info./cmpingstatus [server]— Show full monitoring results sorted from newest to oldest, with an optional server filter./cmpingfail [server]— Show currently failed links with an optional server filter./cmpingevents [id]— Show CMPing incident log or detailed incident breakdown (aliases:/cmpingincidents,/cmevents)./cmpinghistory [server]— Show downtime records and outage durations for monitored servers (alias:/cmhistory)./cmreport <on/off>— Toggle monitoring alerts for current chat (Admin only).
Relay selection and failover are handled by the Delta Chat core (2.61+): it sends via the newest relay first and falls back to the next one if a relay is unreachable. /transports lists relays in that order. The former /setprimary and /resilient commands are deprecated and only reply with this explanation.
Target-Specific Commands in Group Chats
In group chats where multiple bots are present, you can address this bot specifically to prevent other bots from responding. Append the @boun or @stew suffix to any command, for example:
/help@bounor/help@stew/stats@bounor/stats@stew
A plain /help sent in a group chat is answered in a private 1:1 chat with the sender, so several bots don't flood the group with help texts. Use /help@boun to show the help in the group itself.
Admin Management
Admin functions can be performed directly through chat commands, or managed via the server CLI:
Set Administrator
docker compose exec bot python set_admin.py --email your@email.com
Transport (Mail Relay) CLI Initialization
Although we recommend using /addtransport in chat, you can also add a backup relay via the command line:
- Stop the bot:
docker compose stop bot - Add relay:
docker compose run --rm bot python bot.py init transport backup-email@example.com password - Start the bot:
docker compose up -d
Storage Optimization & Cleanup
To keep server disk usage to an absolute minimum, the bot is configured to:
- Disable Auto-Downloads: Disables downloading any attachments/media files automatically (
download_limitis set to1byte). The bot only processes message text. - Auto-Delete Old Messages: Automatically deletes messages older than 36 hours (
delete_device_afterset to36 hours/ 1.5 days) to prevent the main SQLite database (dc.db) from growing while preserving a buffer for/top24-hour activity stats.
Safe Disk Space Cleanup
If the bot's data directory has already grown due to old media attachments, you can safely delete all cached media files (blobs) on your host system without breaking the SQLite database:
# Clean up existing downloaded attachments/blobs
rm -rf /home/tgbridge/deltachat_bouncer/data/bouncer/accounts/*/dc.db-blobs/*
Fediverse / ActivityPub Federation
Every channel registered in the Bouncer Bot automatically federates with the Fediverse (ActivityPub / ActivityStreams 2.0).
Following a Channel from Mastodon / Fediverse
-
In your Mastodon (or Pleroma, Misskey, etc.) search bar, search for the channel handle:
@<channel_token>@dc.gluek.info(For example:
@twniAE9eNajd@dc.gluek.info) -
Click Follow. The bot will automatically accept your follow request.
-
When new messages and media (images, videos, files) are posted to the Delta Chat channel, they will automatically appear in your Mastodon home feed as rich posts.
Supported Endpoints
- WebFinger:
/.well-known/webfinger?resource=acct:<token>@<domain>(RFC 7033) - Actor Profile:
/c/{token}(Content Negotiation withAccept: application/activity+json, includes avatar icon and background wallpaper header banner) - Actor Inbox & Shared Inbox:
/c/{token}/inboxand/inbox(ReceivesFollow,Undo, andDeleteactivities; sendsAcceptand backfills up to 10 recent channel posts to the new follower's inbox) - Actor Outbox:
/c/{token}/outbox(ReturnsOrderedCollection/OrderedCollectionPagewith recent channel notes) - Actor Followers & Following:
/c/{token}/followers(Returns follower count) and/c/{token}/following - Single Note:
/c/{token}/posts/{msg_id}(Direct post representation with ActivityStreams@context) - NodeInfo & Instance API:
/.well-known/nodeinfo,/nodeinfo/2.0, and/api/v1/instance(Instance metadata and stats for GoToSocial, Mastodon, and crawlers)
All outgoing federation deliveries are cryptographically signed using HTTP Signatures (draft-cavage-http-signatures) with individual RSA-2048 actor keypairs.
Architecture
As of v2.15.0, the bot logic is split into focused modules instead of one monolithic file (bot.py is now the lifecycle entry point only — on_init/on_start/__main__):
config.py— static configuration: env loading, logging, version, cooldown/constant tables, thedc_cliinstance.state.py— mutable runtime state: locks, caches, the live bot handle. Other modules always read/write it asstate.<name>.dc_helpers.py— generic Delta Chat RPC helpers (admin/fingerprint checks,_send/_react, the delayed-command debouncer, message-attachment extraction).formatting.py/security.py— Delta Chat markdown → HTML rendering; web-layer rate limiting and safe host/URL resolution.moderation.py,transports.py,cmping.py+cmping_commands.py,channels.py,virustotal.py,stickers.py— one module per subsystem, each owning its background workers and/commandhandlers.commands.py/handlers.py— the remaining general commands (/help,/bounce,/search, …) and the global Delta Chat event handlers (system messages, the catch-allNewMessagedispatcher).web/— the aiohttp channel-preview + ActivityPub server:web/routes.py,web/ap_routes.py, andweb/templates/(landing page, channel preview, RSS feed, tombstone/404, shared theme snippets).
bot.py re-exports everything under its old name for backward compatibility (import bot; bot.<name> still works), but new code should import the owning module directly.
Support & Development
If you find this bot useful, consider supporting its development:
- Git: gluek/deltachat_bouncer
- Donations: Use the
/donatecommand in Delta Chat.