- Python 99.6%
- 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 | ||
| tests | ||
| .dockerignore | ||
| .gitignore | ||
| bot.py | ||
| caching.py | ||
| CHANGELOG.md | ||
| cleanup_db.py | ||
| CONTEXT.md | ||
| database.py | ||
| dc_commands.py | ||
| dc_events.py | ||
| dc_helpers.py | ||
| debug_resolve.py | ||
| docker-compose.yml | ||
| Dockerfile | ||
| formatting.py | ||
| icon_deltachat.jpg | ||
| icon_deltachat.png | ||
| live_locations.py | ||
| logging_setup.py | ||
| media.py | ||
| PERMISSIONS.md | ||
| README.md | ||
| relay.py | ||
| requirements.txt | ||
| restore_channels.py | ||
| rpc_proxy.py | ||
| runtime_patches.py | ||
| security.py | ||
| set_admin.py | ||
| tg_commands.py | ||
| tg_events.py | ||
| update.sh | ||
| userbot.py | ||
Delta Chat ↔ Telegram Bridge Bot
A bot that acts as a bridge between Delta Chat groups and Telegram groups. It relays messages sent in mapped Telegram groups to corresponding Delta Chat groups, and vice-versa.
Built using deltabot-cli-py and python-telegram-bot (asyncio).
Key Features
-
Bidirectional Group Bridging: Sync messages between Telegram groups and Delta Chat groups.
-
Bidirectional Deletion Sync: Sync message deletions between both platforms with built-in safety guards.
-
Bidirectional Edit Handling: Edits are synced in-place in both directions. Telegram → Delta Chat edits are processed via the message editing protocol (with delete-and-resend fallback), and Delta Chat → Telegram edits are synced using Telegram's API for editing text and captions.
-
Public Telegram Channels: Bridge any public channel to a Delta Chat broadcast group.
-
Rich Text & Advanced Formatting Support: Full conversion of Telegram's rich text formatting (bold
**text**, italic*text*, underline__text__, strikethrough~text~, spoiler||text||, inline code`code`, code blocks```lang\ncode\n```, blockquotes> text, expandable blockquotes, hyperlinks[text](url), and headers) into native Delta Chat Markdown. -
Telegram Paid Media & Extended Post Types: Full support for relaying Telegram Paid Media (posts/photos/videos locked with Telegram Stars), Stories, Giveaways, Polls, Contacts, Invoices, and new Telegram post formats without skipping posts.
-
Telegram RichMessage & Inline Media Support: Native decoding and relay of posts created with Telegram's Rich Text Editor (featuring inline images, headings, blockquotes, code blocks, lists, and tables interleaved directly inside text, as introduced in Telegram MTProto Layer 229+). Downloads inline media directly via Telethon MTProto without relying on Telegram's web viewer.
-
Public Post Web Recovery & Unsupported Media Handling: Automatic fallback extraction of public channel posts when Telegram MTProto returns unsupported media objects or rich post containers, preventing cryptic
[MessageMediaUnsupported]placeholders and ensuring posts without displayable content fall back gracefully to Telegram web links instead of generating empty WebXDC packages. -
Telegram Rich Post, Video & Album WebXDC Packaging: Automatically packages long-form Telegram channel posts (with tables, spoilers, blockquotes), video posts, and multi-image albums into standalone, interactive WebXDC applications (
.xdc). Apps feature offline reading and video playback:- Inline Article Rendering: Rich Telegram articles (created with Telegram's Rich Text Editor) are rendered as true articles inside the WebXDC app: inline images, figures, and captions appear embedded directly in the article body at the correct position, matching the original Telegram reading experience. All
PageBlocktypes are fully supported (paragraphs, photos, collages, slideshows, videos, blockquotes, lists, code blocks, and expandable details — always shown fully expanded). - Unified Gallery Lightbox: All images in a post (both top gallery and inline article images) participate in a single shared gallery lightbox with previous/next navigation, thumbnail strip, caption, image counter, keyboard arrow keys (←/→/Esc), and touch-swipe gestures.
- Embedded Video Playback: Direct HTML5
<video controls playsinline preload="metadata">playback inside the WebXDC app for videos up to 20 MB individually and up to 50 MB total cumulative budget across multiple videos. MP4 streams are stored without CPU-heavy re-encoding for instant packaging and smooth playback across mobile and desktop. - Smart Overflow Handling: Videos exceeding 20 MB, exceeding the 50 MB package budget, or marked as "Media is too big" by Telegram web embeds are rendered as elegant preview cards with duration badges, poster images, and a prominent «View all videos in Telegram ↗» button linking directly to the Telegram post.
- Image, UI & Title Formatting: Bundles optimized WebP images (max 1280px, matching Telegram's native resolution), channel avatars (128x128 PNG icon extracted directly from local Delta Chat channel cache), dark/light theme (
prefers-color-scheme), interactive spoilers, table wrapping, lightbox viewer, clear app card titles (Channel Title #PostID), and an attribution footer (Post bridged at ... by Delta Chat Telegram Bridge) linking to Telegram and source repository. Configurable via/richmode(webxdc,split,both, oroff). - Persistent Media Group Deduplication: Media groups and multi-photo albums are tracked persistently in SQLite (
processed_media_groups) with mapping of all individual album message IDs intomessage_map, preventing duplicates across restarts, delayed arrivals, and edit events.
- Inline Article Rendering: Rich Telegram articles (created with Telegram's Rich Text Editor) are rendered as true articles inside the WebXDC app: inline images, figures, and captions appear embedded directly in the article body at the correct position, matching the original Telegram reading experience. All
-
Direct Telegram Post Link Previews & WebXDC Packaging: Automatically intercepts direct Telegram post links (
https://t.me/{channel}/{post_id}orhttps://t.me/s/{channel}/{post_id}) sent in Delta Chat groups and 1:1 direct chats. Posts are processed using the native MTProto / WebXDC pipeline according to/richmode(plain text for text-only posts, photo with caption for single-image posts, and interactive WebXDC.xdcapps for rich posts, multi-photo albums, and videos). Includes persistent SQLite caching (telegram_post_cache, 24h TTL) to ensure instantaneous 0ms responses on repeated links and prevent Telegram MTProto FloodWait rate limits. -
Channel Sync Command (
/channelssync): Force-refresh names and avatars of all bridged channels from Telegram (supports both Bot API and Userbot). -
Historical Context: Automatically pre-fills newly bridged channels with the last 3 historical posts.
-
Userbot Mode: Bridge channels without needing administrator permissions.
-
Watchdog & Polling Timeout Optimization: Automatic detection and recovery from both Userbot and Telegram Bot API polling connection hangs. Configured tuned
get_updates_requestHTTP timeouts (read_timeout=60s,connect_timeout=30s) and log filters to suppress transienthttpcore.ConnectTimeouterrors during polling restarts and graceful shutdowns. -
Automatic Bridge Cleanup & Reconciliation Worker: Automatic startup and daily background cleanup worker to detect and remove orphaned database records, purge empty duplicate bridges (
0 👤) for the same Telegram chat, delete dead fallback ghost groups from Delta Chat, and reconcile broadcast channels. -
Automatic Transport Failover: Link multiple mail relays to a single account. The bot automatically detects message delivery failures via raw core events, rotates
configured_addrto the next transport in round-robin fashion, and schedules a resend of the message using exponential backoff (5s, 10s, 20s, 40s...) via an asynchronous timer thread (up to a maximum of 10 attempts per message) to prevent loop propagation and CPU spikes. -
Transport Statistics: Detailed tracking of messages sent and received per relay, viewable via
/transports. -
Rate Limiting & Safety: Global outgoing limits and bulk-deletion protection with admin notifications.
-
Automatic Updates: Self-updating via a simple script and cron job.
-
Admin-Only Management: Securely bridge channels and groups with restricted access.
Prerequisites
- Python 3.9+ (for local/venv setup)
- Telegram Bot token (create a new bot and obtain one from @BotFather)
- Delta Chat account (can be automatically created during setup by providing a valid email address, e.g. from one of public chatmail relays, and a random password)
Installation
-
Clone or navigate to this directory:
cd deltachat_telegram_bridge -
Create a virtual environment and install dependencies:
python3 -m venv venv source venv/bin/activate pip install -r requirements.txt
Setup and Running (Local / venv)
-
Initialize the Delta Chat account Configure your bot's Delta Chat account using
init dc:venv/bin/python bot.py init dc YOUR_DELTA_CHAT_EMAIL YOUR_EMAIL_PASSWORDThis saves the account configuration locally, by default in your OS config directory under
tgbridge(e.g. on linux it is located at~/.config/tgbridge, on macOS it is located at~/Library/Application\ Support/tgbridgeetc). -
Initialize the Telegram Token Configure your bot's Telegram API token. You can pass it as an argument or enter it interactively to keep it out of your command history:
venv/bin/python bot.py init tgThis saves the token locally in the
bridge.dbdatabase. -
Start the bridge bot Once initialized, run the
servecommand to start the relay:venv/bin/python bot.py serve
Setup with Docker Compose (Recommended)
Important
Breaking Change (June 2026): The bot's execution user inside the Docker container has been changed to
root(matching other Delta Chat bots). All configuration and runtime data are now centralized under a single./datadirectory on the host to make backups simpler and cleaner.If you are migrating from an older installation:
- Stop the bot:
docker compose down- Create the
./datadirectory:mkdir -p data- Move your existing data to the new structure:
mv bridge.db data/bridge.db mv userbot_session.session data/userbot_session.session # If you had account configuration in ~/.config/tgbridge: mv ~/.config/tgbridge data/tgbridge- Pull the latest code and start the bot:
./update.sh(ordocker compose up -d --build).
Instead of using a local virtual environment, you can run the bot using Docker Compose:
-
Initialise the database and accounts using
docker compose run:docker compose run --rm bridge python bot.py init dc me@example.com MyPassword docker compose run --rm bridge python bot.py init tg -
Start the bridge:
docker compose up -d -
To update the bot manually after pulling new code:
docker compose up -d --buildYour configuration and message history will be preserved since they are stored in the mounted
./datadirectory.
Configuration (Environment Variables)
The bot supports customizing message retention and attachment size limits via environment variables. If you are using Docker Compose, you can define these in the .env file in the same directory as docker-compose.yml:
| Environment Variable | Description | Default Value |
|---|---|---|
DELETE_DEVICE_AFTER |
Local message retention duration (in seconds). Delta Chat core automatically deletes messages older than this. | 604800 (7 days) |
MAX_ATTACHMENT_SIZE_MB |
Maximum size of attachments to download and relay (in megabytes). Files larger than this will be skipped. | 50 |
Setting Environment Variables
Create or edit the .env file in the project root:
# Retain messages on device for 3 days (259200 seconds)
DELETE_DEVICE_AFTER=259200
# Set maximum attachment size limit to 20 MB
MAX_ATTACHMENT_SIZE_MB=20
Apply the changes by restarting the container:
docker compose down
docker compose up -d
Note: The local message retention duration (DELETE_DEVICE_AFTER) is applied to all active Delta Chat accounts on startup.
Automatic Updates
The repository includes an update.sh script that automates the update process. It performs the following steps:
- Runs
git fetchto check for new commits on the remote repository. - Compares the local version with the remote version.
- If new changes are found, it runs
git pull, rebuilds the Docker container (--build), and cleans up old images.
Setting up a Cron Job
To have the bot automatically check for updates every 15 minutes, you can set up a cron job:
-
Open your crontab:
crontab -e -
Add the following line (replace
/path/to/with the actual absolute path to the project directory):*/15 * * * * /path/to/deltachat_telegram_bridge/update.sh >> /path/to/deltachat_telegram_bridge/update.log 2>&1
Tip
You can find the absolute path by running
realpath update.shinside the directory.
-
Maintenance and Cleanup:
To stop the bot and remove containers:
docker compose downTo remove old, unused images (reclaim disk space):
docker image prune -fTo view logs in real-time:
docker compose logs -f
Usage: Bridging Groups
The bot needs to be added to the Telegram group. When you bridge from Telegram, the bot automatically creates the corresponding Delta Chat group.
Note: By default, management commands (
/bridge,/unbridge,/id) are restricted to group admins. However, if you configure a global admin usinginit admin_dcorinit admin_tg, only the configured bot owner (and designated sub-admins) will be able to manage the bot. The bot's help message will indicate its current state as Mode: Private (bot owner only) or Mode: Public (group admins only).Important: You must disable Group Privacy for your Telegram bot via @BotFather → Bot Settings → Group Privacy → Turn off. Otherwise the bot cannot read normal group messages. After changing this, re-add the bot to the group.
From Telegram (recommended)
- Add your Telegram bot to the target Telegram group.
- Send
/bridgein the group (admin only). The bot will automatically create a Delta Chat group with the same name and avatar, link them, and reply with an invite link to join the DC group. - To remove the bridge, send
/unbridgein the Telegram group.
From Delta Chat (advanced)
- Get the Telegram Group ID by sending
/idin the TG group. - Add your Delta Chat bot to the target Delta Chat group.
- Send
/bridge -100123456789in the DC group (owner only in private mode). - To remove the bridge, send
/unbridgein the DC group.
Note: Group mappings are saved locally in the bridge.db SQLite file (or data/bridge.db when using Docker).
Reactions: For reaction bridging (TG → DC) to work, the bot must be an administrator in the Telegram group. No special permissions are needed — just the admin role. When a basic group is promoted, Telegram may migrate it to a supergroup (changing the chat ID). The bot detects this automatically and updates its stored mappings.
Security Notes
-
The
bridge.db(ordata/bridge.dbwhen using Docker) file contains your Telegram bot token in plaintext. Protect it with appropriate file permissions (e.g.chmod 600 data/bridge.db). -
Management commands (
/bridge,/unbridge,/id) are restricted to group admins or bot owner (see below). -
Messages are rate-limited to 30 messages per minute per chat to prevent flooding.
-
Global outgoing limit: The bot enforces a global limit of 60 messages per minute across all Delta Chat interactions to stay within chatmail server limits.
-
Deletion Safety Guard: To prevent accidental data loss, the bot limits automatic deletion sync to 5 messages per 60 seconds. Bulk deletions are blocked and reported to the admin. Note: technical deletions (like replacing an old message during an edit fallback) are exempt from this limit.
-
Sender names are HTML-escaped before being sent to Telegram to prevent injection.
-
Bot messages from both sides are filtered out to prevent echo loops.
Logging and Admin Control
-
Set Global Admin (Telegram): Configures a Telegram user ID to receive bot error logs via direct message (similar errors are sent at most once per hour, with a count of suppressed repeats). (You can find your Telegram ID by sending
/startto the bot in a private message). Important Note: Settingadmin_tglocks the Telegram management commands so that only this user can manage the bot (the help text will dynamically change to Mode: Private (bot owner only)).docker compose exec bridge python bot.py init admin_tg YOUR_TELEGRAM_ID -
Set Global Admin (Delta Chat): Configures a Delta Chat email to receive bot error logs via direct message (similar errors are sent at most once per hour, with a count of suppressed repeats). Important Note: Setting
admin_dclocks the/bridgeand/unbridgecommands so that only this user can use them (the help text will dynamically change to Mode: Private (bot owner only)).docker compose exec bridge python bot.py init admin_dc admin@example.com -
Add Backup Relay (Transport): Link multiple mail servers. 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. The former
/setprimaryand/resilientcommands are deprecated and only reply with this explanation.docker compose stop bridge docker compose run --rm bridge python bot.py init transport backup@example.com "PASSWORD" docker compose up -d
Other Commands
Since the bot depends on deltabot-cli-py, you have access to a variety of other management commands. These commands do not require the --telegram-token argument.
If you are using Docker, run these commands using docker-compose exec bridge python bot.py ... (if the bot is running) or docker-compose run --rm bridge python bot.py ... (if stopped).
If you are running locally, use venv/bin/python bot.py ....
Here are the commands (shown for Docker, assuming the container is running):
-
Get Invite Link (QR Code data): Print the bot's invitation link so you can add it to Delta Chat groups.
docker compose exec bridge python bot.py link -
List accounts: View the IDs and addresses of configured Delta Chat accounts.
docker compose exec bridge python bot.py list -
Config: View or set configuration options for the bot account.
docker compose exec bridge python bot.py config -
Remove account: Remove a specific Delta Chat account if you accidentally created multiple. Replace
IDwith the account number (e.g.2).docker compose exec bridge python bot.py --account ID remove -
Admin: Generates a setup QR code to join an Admin control group where you can manage the bot remotely.
docker compose exec bridge python bot.py admin
For more details on management commands, see the deltabot-cli-py repository.
Sub-Admins (Private Mode)
In private mode (admin_tg is set), the bot owner can designate sub-admins who can independently manage their own bridges and channels.
Sub-admins can:
- Use
/bridgeand/unbridgein Telegram groups - Use
/channeladdand/channelremovefor channels - View their own bridges via
/statsand/channels
Sub-admins cannot see or manage resources created by the owner or other sub-admins.
| Command | Description |
|---|---|
/adminadd <user_id> |
Add a sub-admin (owner only, private chat) |
/adminremove <user_id> |
Remove a sub-admin (owner only, private chat) |
/admins |
List all sub-admins (owner only, private chat) |
Channel Bridging (TG Channel → DC Broadcast)
The bot can bridge Telegram channels and groups to Delta Chat broadcast channels (one-way, read-only).
Note: By default, the bot requires being an administrator in a Telegram channel to receive posts. If you cannot make the bot an admin, or you want to bridge a regular group in "stealth" read-only mode, you can enable Userbot Mode.
Setup
-
Add the bot as an admin to the Telegram channel you want to bridge.
Alternatively, if you cannot add the bot as admin, configure Userbot Mode and use/userbotjoinfirst. -
In a private chat with the bot, use
/channeladd @channel_usernameor/channeladd -1001234567890(numeric ID) to create the bridge.- Tip: When you add the bot as an administrator to a channel, it will automatically send a private message to the configured
admin_tgwith the channel's numeric ID and a ready-to-use bridging command. - Tip: If the bot is not an admin but Userbot is configured and has joined the channel,
/channeladdwill automatically fall back to Userbot mode.
- Tip: When you add the bot as an administrator to a channel, it will automatically send a private message to the configured
-
The bot will create a DC broadcast channel (with the same name and avatar) and return an invite link for subscribing.
Commands (private chat, admin/sub-admin)
| Command | Description |
|---|---|
/channeladd <target> |
Create a bridge for a TG channel, group, or Bot (bot as admin, or Userbot) |
/channelremove <target> |
Remove a channel bridge (alias: /channeldelete) |
/channels |
List bridged channels (as admin, private chat) |
/channel N |
Get invite link for channel by its internal number |
/channelqr N |
Get QR code image for channel by its internal number |
/botsend <target> <text> |
Send command or message to a bridged TG bot (e.g. /botsend @weather_bot /today) |
/filters |
List active message filters (owner only) |
/filteradd <phrase> |
Add a keyword or phrase filter (e.g. /filteradd #реклама) |
/filterdel <target> |
Remove a filter by number or phrase (alias: /filterremove) |
/userbotjoin <link> |
Join a channel/group via Userbot (no admin needed) |
/groups |
List technical account's groups for easy bridging |
/cleanup |
Clean up stale, duplicate & orphaned bridges (owner only) |
/catchup |
Catch up missed channel posts on demand (optional @channel) (admin only) |
/initadmin |
Claim bot ownership in private chat (binds email & cryptographic fingerprint) |
/transports |
Show configured mail relays & usage stats |
/addtransport <addr> |
Add a backup mail relay (private 1:1 chat only, chatmail URI or addr password) |
/rmtransport <addr> |
Remove a mail relay |
/richmode [mode] |
Configure rich post relay mode (webxdc, split, both, off) |
/status |
Show detailed bot, userbot, queue, and channel status (admin only) |
/donate |
Support bot development ❤️ |
Message & Post Content Filters
The bot includes unified keyword and phrase filtering for all bridged channels and group chats. When an incoming Telegram post, edit, or group message contains any filtered word or phrase (case-insensitive substring match), it is skipped and not relayed to Delta Chat.
/filters— Show all active filters with their numbered IDs./filteradd <word or phrase>— Add a filter (e.g./filteradd #рекламаor/filteradd erid=)./filterdel <number or phrase>— Remove a filter by its ID number from/filtersor by exact text (alias/filterremove).
Delta Chat User Commands
Any Delta Chat user (not just admins) can use these commands in a private chat with the bot or in a group:
/channels— List all available public Telegram channels (shows TG and DC stats)./channelN— Get the text invite link for channel #N (e.g.,/channel5)./channelNqr— Get the QR code invite for channel #N./donate— Support bot development ❤️
Management (Admin only)
/initadmin— Claim bot ownership in private chat (binds email & cryptographic fingerprint)./channeladd @username— Bridge a new channel (admin email check)./channelremove N— Remove bridge for channel #N (alias/channeldelete)./filters— List active message filters./filteradd <phrase>— Add a keyword/phrase filter./filterdel <id or phrase>— Remove a message filter./catchup [@channel]— Catch up missed posts for a channel or all channels./userbotjoin <link>— Join channel via Userbot (invite link support)./channelNqr— Get the QR code image for channel #N (for easy sharing/onboarding)./cleanup— Clean up stale, duplicate & orphaned bridges./stats— Show bridge statistics for the current chat./status— Show detailed bot, userbot, queue, and channel status (admin only)./transports— Show configured mail relays & usage stats./addtransport <addr>— Add backup mail relay (private 1:1 chat only)./rmtransport <addr>— Remove mail relay./richmode [mode]— Configure rich post / album relay mode (webxdcfor interactive WebXDC apps,splitfor separate follow-up images,bothfor WebXDC + extra images, orofffor legacy fallback)./help— Show Delta Chat bot help.
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 @tg or @tgbridge suffix to any command, for example:
/help@tgor/help@tgbridge/stats@tgor/stats@tgbridge
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@tg to show the help in the group itself.
Userbot Mode (Bridging without Admin permissions)
If you want to bridge channels where you cannot add the bot as an administrator, you can configure Userbot Mode. This allows the bot daemon to act as a regular Telegram client using your personal account.
1. Obtain API Credentials
- Go to my.telegram.org and log in.
- Go to API development tools.
- Create a new application (e.g., "DC-TG-Bridge").
- Copy your App api_id and App api_hash.
2. Configure Credentials
Run these commands inside your environment (or via docker-compose exec bridge python bot.py ...):
python bot.py init api_id YOUR_API_ID
python bot.py init api_hash YOUR_API_HASH
3. Initialize Interactive Login
This step requires entering your phone number and the SMS/Telegram validation code. If using Docker, you must run it interactively:
docker compose exec bridge python bot.py init userbot
Tip
If Telegram sends a login code to your technical account itself, the bot will automatically capture it and forward it to you via Delta Chat and Telegram.
4. Security Risks
Caution
Using your personal account for Userbot Mode comes with risks:
- Session Security: A file named
userbot_session.sessionwill be created. This file is essentially a "master key" to your Telegram account. Never share it. Ensure your server has strict file permissions.- Account Activity: The bot will join channels on your behalf to read posts.
- API Limits: While safe for moderate use, intensive API operations can theoretically lead to temporary rate limits or account flags from Telegram's anti-spam systems. It is recommended to use a dedicated "feeder" account if you plan to bridge a very large number of channels.
5. Bridge the Channel
Once the Userbot is configured and has joined the channel (via /userbotjoin):
- In a private chat with the bot, use
/channeladd @channel_usernameor/channeladd -1001234567890. - The bot will automatically use the Userbot to resolve the channel and relay messages — no admin rights needed.
Note:
/channeladdalways tries the Bot API first. If the bot is not an admin and the Bot API fails, it falls back to the Userbot transparently. You don't need to specify which mode to use.
Double Bridge Protection
If a channel is bridged via both the core bot (as admin) and Userbot Mode, the bridge will automatically deduplicate messages, ensuring Delta Chat users receive only one copy of each post.
Development and Testing
The repository contains a unit test suite covering database operations, rate limits, and helper logic. Since native Delta Chat C-libraries and account setups are mocked, the tests can be run locally in any standard Python environment.
To run tests locally:
python -m unittest discover -s tests -p "test_*.py" -v
Tests are also executed automatically via GitHub Actions on every push to the master branch.
Changelog
See CHANGELOG.md for a detailed history of changes.