An asynchronous Telegram message forwarding bot with a modern Python architecture, built with Telethon and Rich.
This project is based on the original Telegram Forwarder Bot by Mohammad Shabib.
- 🚀 Async/Await: Fully asynchronous architecture for high performance
- 🔄 Live Forwarding: Real-time message forwarding with event handlers
- 📚 History Forwarding: Bulk message forwarding from chat history with date filtering
- 📅 Month Filtering: Forward messages from specific months or date ranges
- 🌍 Timezone-Aware Date Filters: Apply date windows in UTC, local, or custom IANA timezone
- 🔎 Dry-Run Preview: Count matching historical messages before forwarding
- 📊 Progress Tracking: Real-time progress indicators showing completion percentage
- 🔍 Keyword Search Forwarding: Search source chat history by an optional keyword and forward matching (or all) messages, resumable over a date range
- 👥 Multi-Account Support: Switch between multiple Telegram accounts
- 🎯 Rate Limiting: Built-in rate limiting to respect Telegram's API limits
- 🎨 Rich Console UI: Beautiful terminal interface with Rich
- 🌐 Web Dashboard: FastAPI-based web interface for remote management
- 🔒 Secure: Environment variable management for sensitive data
- 📝 Type-Safe: Full type hints throughout the codebase
- 🐳 Docker Support: Containerized deployment with Docker Compose
- Python 3.10 or higher (for local installation)
- A Telegram account with API credentials
- Docker & Docker Compose (for containerized deployment)
Choose one of the following installation methods:
-
Clone the repository:
git clone https://github.com/klept0/Telegram-Forwarder-Bot-v2.git cd Telegram-Forwarder-Bot-v2 -
Create virtual environment:
python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate
-
Install dependencies:
pip install -e ".[dev]" -
Run the bot:
python main.py
You'll be prompted for your Telegram API credentials on first run; they're saved to
resources/credentials.jsonfor reuse (no.envfile needed for the CLI — that's only required if you also run the web dashboard, see Configuration).
-
Clone the repository:
git clone https://github.com/klept0/Telegram-Forwarder-Bot-v2.git cd Telegram-Forwarder-Bot-v2 -
Set up environment variables:
cp .env.example .env # Edit .env and set API_KEY (required by the web service, see Configuration below) -
Authenticate once, interactively, before running detached:
The
telegram-forwardercontainer runspython main.py, which prompts for your Telegram API credentials and login code on first use. Run it attached the first time so you can answer the prompts:docker-compose run --rm telegram-forwarder
This saves a session under
./sessionsand credentials under./resources, which are mounted as volumes — subsequent runs (including thewebservice) reuse that session without prompting again. -
Run with Docker Compose:
docker-compose up --build
Or run in background:
docker-compose up -d --build
-
View logs:
docker-compose logs -f telegram-forwarder
-
Stop the bot:
docker-compose down
Docker Notes:
- Configuration files are stored in Docker volumes for persistence
- The web service's
API_KEYis loaded from the.envfile;docker-compose upfails fast with a clear error if it isn't set - The bot runs as a non-root user for security
-
Clone the repository:
git clone https://github.com/klept0/Telegram-Forwarder-Bot-v2.git cd Telegram-Forwarder-Bot-v2 -
Create virtual environment:
python -m venv .venv source .venv/bin/activate # On Windows: .venv\Scripts\activate
-
Install dependencies with web extras:
pip install -e ".[web]" -
Authenticate an account first, via the CLI:
The web dashboard never prompts for a Telegram login itself — it reuses the session created by the CLI. Run
python main.pyonce, answer the credential/login prompts, then exit; this saves a session under./sessionsand credentials under./resources. -
Set up environment variables:
cp .env.example .env # Edit .env and set API_KEY (the dashboard refuses to serve API # requests without it — see Configuration below)
-
Run the web dashboard:
python web/app.py
Or run from the project root:
python -m web.app
-
Open your browser:
Navigate to
http://localhost:8000to access the web interface. The page will prompt you once for theAPI_KEYvalue and remember it in the browser's local storage for subsequent requests.
Web Interface Features:
- Real-time bot status monitoring
- Forward configuration management
- Chat browser and selection
- REST API for programmatic access
- Remote control of forwarding operations
- Dark mode (follows system preference, toggle in the header)
- Collapsible sections for long lists (Forwarding Configurations, Available Chats)
Telegram account credentials are entered interactively on first run
(python main.py) and stored in resources/credentials.json — they are
not read from environment variables.
The web dashboard (web/app.py) does use environment variables. Create a
.env file in the project root (see .env.example):
# Required: shared secret clients must send as the X-API-Key header on
# every /api/* request. The dashboard refuses to serve requests without it.
API_KEY=change_me_to_a_long_random_value
# Optional: bind address/port for the web dashboard (defaults shown below)
WEB_HOST=127.0.0.1
WEB_PORT=8000- Go to my.telegram.org
- Log in with your phone number
- Go to "API development tools"
- Create a new application
- Copy the
api_idandapi_hash
- Add/Update Credentials - Configure Telegram API credentials
- List Chats - Display all available chats
- Delete My Messages - Remove your messages from chats
- Find User Messages - Search for messages from specific users
- Live Forward Messages - Start real-time message forwarding
- Past Forward Messages - Forward historical messages
- Keyword Search + Forward - Search by keyword and forward matching messages
- Forward Media Files (Files/Images) - Forward all files/images (optionally keyword-filtered) from a date range, in the order they were posted
- Switch Account - Change between configured accounts
- Clear Forward Progress Cache - Reset saved resume state for historical forwarding
- Exit - Close the application
Configure message forwarding by specifying:
- Source Chat: The chat to forward messages from
- Destination Chat: The chat to forward messages to
- Date Filtering: Choose from:
- No date filter (forward all messages)
- Filter by specific month
- Filter by multiple months
- Filter by custom date range
- Timezone: Choose UTC, local system timezone, or custom IANA timezone
- Dry-Run Preview: Optional count-only run without sending messages
- Enabled: Whether forwarding is active
When forwarding historical messages, the bot displays real-time progress indicators showing:
- Number of messages found
- Current progress (X/Y messages)
- Percentage completion
Use the Keyword Search + Forward menu option to:
- Select source and destination chats
- Optionally enter a keyword to search in source chat history — leave it blank to forward every message in range instead of filtering by keyword
- Optionally set date range + timezone filtering
- Run dry-run preview (count matches only) or forward matches
Matching messages are forwarded in chronological order. When a date range is
selected, this is resumable: re-running the exact same source, date range,
and keyword — whether the previous run finished or was interrupted — checks
what's already been forwarded and only sends what hasn't been, instead of
duplicating messages. Use Clear Forward Progress Cache to force a full
re-scan of a range you've already run.
Use the Forward Media Files menu option to forward only messages that
carry a file, photo, or video from a source chat's history — in the order
they were originally posted:
- Select source and destination chats
- Optionally filter to files whose caption/text matches a keyword
- Pick a date range (no filter, a specific month, multiple months, or a custom range — e.g. "all of June")
- Timezone selection and dry-run preview, same as the other forward flows
Dry-run preview reports the total number of matching files, not an
estimate. Real runs are resumable: if you re-run the exact same source,
date range, and keyword/media combination — whether the previous run
finished or was interrupted — it picks up right after the last file it
already forwarded instead of sending duplicates. To force a full re-scan
of a range you've already run, use Clear Forward Progress Cache first.
The web interface provides a REST API for programmatic access. Every
/api/* route requires an X-API-Key header matching the server's
API_KEY environment variable (see Configuration):
curl -H "X-API-Key: $API_KEY" http://localhost:8000/api/statusGET /api/status- Get real-time bot status
GET /api/chats- List available Telegram chats
GET /api/forwards- List all forwarding configurationsPOST /api/forwards- Create new forwarding configurationDELETE /api/forwards/{source_id}- Delete forwarding configurationPOST /api/forwards/{source_id}/toggle- Enable/disable forwarding
POST /api/start-forwarding- Start live message forwardingPOST /api/stop-forwarding- Stop live message forwarding
POST /api/keyword-forward- Forward messages in a source chat, optionally filtered by keyword (omitkeywordto forward everything in range) — supports dry-run and, with a date range, resumes without re-forwarding what was already sent
telegram-forwarder-bot-v2/
├── source/
│ ├── core/
│ │ ├── __init__.py
│ │ ├── Bot.py
│ │ └── Telegram.py
│ ├── dialog/
│ │ ├── __init__.py
│ │ ├── BaseDialog.py
│ │ ├── ForwardDialog.py
│ │ └── ...
│ ├── menu/
│ │ ├── __init__.py
│ │ ├── AccountSelector.py
│ │ └── MainMenu.py
│ ├── model/
│ │ ├── __init__.py
│ │ ├── Chat.py
│ │ ├── Credentials.py
│ │ └── ...
│ ├── service/
│ │ ├── __init__.py
│ │ ├── MessageQueue.py
│ │ ├── MessageForwardService.py
│ │ └── ...
│ └── utils/
│ ├── __init__.py
│ ├── Console.py
│ └── Constants.py
├── web/
│ ├── __init__.py
│ ├── app.py
│ ├── static/
│ ├── templates/
│ └── README.md
├── docs/
│ ├── conf.py
│ ├── index.rst
│ └── Makefile
├── tests/
├── .env.example
├── .gitignore
├── .pre-commit-config.yaml
├── Dockerfile
├── docker-compose.yml
├── main.py
├── pyproject.toml
├── requirements.txt
└── README.md
Install the dev tools, then run the same checks CI runs:
pip install -e ".[dev]"
ruff check source/ tests/
ruff format --check source/ tests/
mypy source/
pytest tests/ --cov=sourcepip install -e ".[docs]"
cd docs
make html # output in docs/_build/html/- Bot: Main application orchestrator
- Telegram: Telethon client wrapper with service integration
- Services: Business logic layer (Forwarding, Queue, Chat management)
- Models: Data persistence and validation
- Dialogs: User interaction flows
- Utils: Shared utilities and constants
- Live Mode: Event handlers capture new messages → Queue → Rate-limited forwarding
- History Mode: Bulk message retrieval → Process in batches → Forward with rate limits
- Configuration: Source/destination chat mapping via ForwardConfig model
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
- Follow PEP 8 style guidelines
- Add type hints to all functions and methods
- Update documentation for API changes
- Use conventional commit messages
CHANGELOG.md is maintained as a running log for every update. Each release entry should include:
Added/Changed/Fixeddetails- Explicit behavior delta when relevant (before vs after)
- Release date and semantic version
- Never commit API credentials or sensitive data (
resources/credentials.jsonandsessions/are gitignored) - The web dashboard requires an
API_KEYand refuses to serve/api/*requests without one; it binds to127.0.0.1by default - Regularly update dependencies for security patches
- Follow principle of least privilege
This project is licensed under the MIT License - see the LICENSE file for details.
- Telethon - Telegram client library
- Rich - Beautiful terminal output
- FastAPI - Modern web framework
- Pydantic - Data validation
- Loguru - Structured logging
- Uvicorn - ASGI server
If you find this project helpful, please give it a ⭐️!
For questions or issues:
- Open an issue
- Check the documentation