← All notes

Engineering · 30.06.2026

Throttling a DM send so Telegram never notices

Bulk messaging lives and dies by restraint. Telegram's documented limit is roughly 30 messages per second; the thresholds that actually get bots restricted are lower, unpublished, and partly behavioural.

Antenna's planner therefore never trusts the client with a rate. The server computes batches from constants: a per-second ceiling well under 30, and for larger lists a spread across hours rather than minutes. A 10,000-recipient send unrolls into small batches separated by deliberate gaps, with the schedule persisted server-side so a restart can't accelerate it.

The batch runner treats every response code as information. A 429 with retry_after backs the whole stream off — globally, not just for one recipient. A Forbidden: bot was blocked by the user marks that one subscriber blocked and moves on; they're never charged and never retried. Anything unexpected pauses the job and surfaces the reason in the dashboard.

Credits follow the same discipline. The full estimated cost reserves at start; as the batch completes, the reservation settles down to actual deliveries and the unused part returns. If the balance runs dry mid-send, the job stops cleanly — delivered-so-far is settled, the remainder is cancelled, and the owner is told, not left guessing.

Conservative numbers cost a little latency. They buy the one thing a shared bot can't repurchase: its standing.