Telegram Channel

Telegram Outreach

Automated Telegram messaging using Telethon user accounts with intelligent account pooling, rate limiting, and warmup tracking.

Why User Accounts?

The Telegram Bot API cannot initiate DMs to users who have not started the bot. User accounts (via Telethon) can message anyone by username, which is critical for outreach campaigns. Account pooling distributes risk and increases throughput.

Architecture

telegram-worker/
telegram-worker/
├── main.py              # FastAPI app with all endpoints
├── account_manager.py   # Telethon client pool + auth flow + send logic
├── db.py                # Database operations (messages, accounts)
├── config.py            # Environment config (rate limits, delays)
├── requirements.txt
└── Dockerfile           # Railway deployment (port 7861)

Worker API Endpoints

POST/api/send
POST/api/accounts/add
POST/api/accounts/:id/verify
GET/api/accounts
GET/api/health

Account Pooling

The Telegram worker manages a pool of user accounts. When a message needs to be sent, it automatically selects the best account based on:

  • Account with the fewest daily sends (load balancing)
  • Daily message limit not exceeded (default: 30/account)
  • Account status is active (not banned, not in cooldown)
  • Account is assigned to the requesting organization

Account Statuses

warming_up

New account, limited sends

active

Ready to send

assigned

Assigned to an org

banned

Blocked by Telegram

cooldown

Temporarily paused

Rate Limiting

The worker implements several layers of rate limiting to avoid Telegram bans:

LimitDefaultConfigurable
Max daily messages per account30MAX_DAILY_MESSAGES_PER_ACCOUNT
Min delay between sends30 secondsMESSAGE_DELAY_MIN
Max delay between sends90 secondsMESSAGE_DELAY_MAX
Inter-lead campaign delay60 secondsHardcoded in executor

Message Flow

Send Message Sequence
POST /api/send { orgId, username, message }
    |
    v
1. manager.get_available_account(orgId)
   -> Select account with fewest daily sends
   -> Check daily limit not exceeded
    |
    v
2. Random delay (30-90 seconds)
    |
    v
3. manager.send_message()
   -> client.get_entity(username)
   -> client.send_message(entity, message)
   -> db.increment_daily_sent()
    |
    v
4. db.log_message() -> INSERT INTO messages
    |
    v
5. Return { success: true, messageId: "..." }