Как делать рассылки по пользователям бота без блокировок
Практика4 минРедакция Innovialabs
Коротко
Отправляйте рассылку через очередь с ограничением скорости, на ошибку 429 ждите ровно retry_after, пользователей с ошибкой 403 помечайте неактивными, а результат считайте по статусам каждого сообщения и переходам по ссылкам.
Короткий ответ
Рассылка без проблем — это очередь с ограничением скорости, а не цикл for user in users: send(). Что нужно:
- Скорость. Telegram в своем FAQ советует не отправлять массовые уведомления быстрее примерно 30 сообщений в секунду и не больше одного сообщения в секунду в один чат. Держите запас ниже этой границы.
- Ошибка 429. Если Telegram ответил
Too Many Requests, ждите столько секунд, сколько указано вretry_after, и повторяйте. - Ошибка 403. Пользователь заблокировал бота или удалил аккаунт. Пометьте его неактивным и больше не пишите.
- Учет. Каждое сообщение получает статус: отправлено, ошибка, заблокировано.
Для больших объемов у Telegram есть платные рассылки: параметр allow_paid_broadcast позволяет превысить бесплатный лимит за Telegram Stars. Подробности и стоимость — в документации Bot API.
Как устроить отправку
- Создайте кампанию в базе: текст, кнопки, сегмент, время старта.
- Сформируйте список получателей — по одной записи на пользователя со статусом
pending. - Воркер берет записи пачками и отправляет с паузой между сообщениями.
- Результат каждой отправки записывается в ту же таблицу:
sent,blocked,failedи ID сообщения. - Повтор выполняется только для
pendingи временных ошибок. Перезапуск воркера не должен отправлять сообщения второй раз.
Для очереди подойдет любой привычный инструмент: Redis, Celery, arq, RabbitMQ или просто таблица в PostgreSQL с блокировкой строк. Важнее, чтобы состояние хранилось в базе, а не в памяти процесса.
Минимальная логика на aiogram 3:
import asyncio
from aiogram.exceptions import (
TelegramForbiddenError,
TelegramRetryAfter,
TelegramBadRequest,
)
async def send_one(bot, user_id: int, from_chat_id: int, message_id: int) -> str:
while True:
try:
await bot.copy_message(user_id, from_chat_id, message_id)
return "sent"
except TelegramRetryAfter as e:
await asyncio.sleep(e.retry_after)
except TelegramForbiddenError:
return "blocked"
except TelegramBadRequest:
return "failed"
async def run_campaign(bot, recipients, from_chat_id, message_id, rate=20):
for user_id in recipients:
status = await send_one(bot, user_id, from_chat_id, message_id)
await save_status(user_id, status)
await asyncio.sleep(1 / rate)
copyMessage удобен для рассылок: вы готовите пост в служебном чате, проверяете его вид, а бот копирует его без пометки «переслано».
Ошибки и что с ними делать
| Ответ Telegram | Причина | Действие |
|---|---|---|
| 429 Too Many Requests | Превышена скорость | Пауза на retry_after, затем повтор |
| 403 Forbidden | Бот заблокирован, аккаунт удален | Пометить is_active = false |
| 400 Bad Request | Чат не найден, неверная разметка, битая ссылка в кнопке | Записать ошибку, не повторять бесконечно |
| 5xx, таймаут | Временный сбой | Повторить с задержкой, ограничить число попыток |
Если вы получаете 429 постоянно, это сигнал снизить общую скорость, а не просто ждать дольше.
Сегментация
Не отправляйте все всем. Сегменты повышают отклик и уменьшают число блокировок:
- Активность: писал боту за последний месяц, давно не заходил.
- Действия: оставил заявку, купил, бросил оформление на середине.
- Источник: пришел по конкретной рекламной ссылке со
start-параметром. - Язык интерфейса или выбранный в боте.
- Согласие: пользователь не отключил уведомления в настройках бота.
Дайте пользователю простой способ отписаться: кнопку или команду. Это лучше, чем блокировка бота, после которой вы теряете контакт полностью.
Как измерить результат
- Доставка: доля
sentот всех получателей, число новыхblocked. - Переходы: ссылки с UTM-метками или deep link вида
t.me/bot?start=camp42, по которому бот понимает, из какой рассылки пришел человек. - Нажатия на inline-кнопки: callback с ID кампании.
- Целевые действия: заявки и оплаты, связанные с кампанией.
- Отписки и блокировки в течение нескольких дней после рассылки.
Факт прочтения Bot API не сообщает, поэтому ориентируйтесь на действия пользователей.
Частые ошибки
- Рассылка из обработчика команды: процесс блокируется, при перезапуске часть людей получает сообщение дважды.
- Параллельная отправка в много потоков без общего ограничителя скорости.
- Игнорирование 403: база «мертвых» пользователей растет, и каждая рассылка тратит на них время.
- Одинаковый текст для всей базы без учета языка и интересов.
Подробнее о лимитах — в FAQ Telegram для разработчиков ботов.