В статье разберём рассылки в Telegram-боте: как отправлять по сегментам, добавлять кнопки и формы, собирать ответы и считать базовую статистику. Примеры на aiogram. Ограничения по отправке: Broadcasting (Telegram FAQ).
Сегментация базы
Подписчиков делят по тегам, по действиям (что нажимали, что покупали) или по дате подписки. Примеры сегментов: «все, кто за месяц нажал „Цены“», «все с тегом VIP». Рассылка уходит только выбранному сегменту — так вы не спамите тех, кому сообщение не подходит.
Пример функции рассылки по тегу. db.get_user_ids_by_tag(tag) — ваш запрос к БД (таблица пользователей с полем tag или отдельная таблица тегов). asyncio.sleep(0.05) снижает риск упереться в лимиты Telegram (порядка 30 сообщений в секунду в один чат). Исключения при send_message часто означают, что пользователь заблокировал бота — их можно логировать или считать.
import asyncio
from aiogram import Bot
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
async def send_broadcast(bot: Bot, tag: str, text: str, button_url: str = None):
user_ids = db.get_user_ids_by_tag(tag) # SELECT user_id FROM user_tags WHERE tag = $1
kb = None
if button_url:
kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Перейти", url=button_url)]
])
sent, failed = 0, 0
for user_id in user_ids:
try:
await bot.send_message(user_id, text, reply_markup=kb)
sent += 1
await asyncio.sleep(0.05) # лимит Telegram ~30 msg/s
except Exception:
failed += 1
return sent, failed # для статистики
Кнопки и формы в рассылке
В сообщение можно добавить inline-кнопки: ссылка на сайт, переход в бота по deep link, запрос обратного звонка. Формы: например «Оставьте email» — по нажатию кнопки бот переводит в состояние FSM и сохраняет введённый email в БД или CRM.
Пример: рассылаем сообщение с кнопкой «Оставить email»; по нажатию включается состояние Form.email, следующий текст пользователя сохраняется. Нужны импорты: from aiogram.fsm.context import FSMContext и from aiogram.fsm.state import State, StatesGroup; класс Form(StatesGroup): email = State().
# Рассылаем сообщение с кнопкой «Оставить email»
await bot.send_message(
chat_id,
"Акция! Оставьте email для уведомлений:",
reply_markup=InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="Оставить email", callback_data="collect_email")]
]),
)
@dp.callback_query(F.data == "collect_email")
async def ask_email(callback: types.CallbackQuery, state: FSMContext):
await state.set_state(Form.email)
await callback.message.answer("Введите ваш email:")
await callback.answer()
@dp.message(Form.email, F.text)
async def save_email(message: types.Message, state: FSMContext):
if "@" in message.text:
db.save_lead(message.from_user.id, message.text) # или отправить в CRM
await message.answer("Спасибо! Мы пришлём уведомление.")
await state.clear()
Статистика открытий
Полезно считать: сколько сообщений доставлено, сколько пользователей заблокировали бота (ошибка при отправке), сколько перешли по ссылке. Переходы по кнопке можно учитывать через короткие ссылки с параметром (например bit.ly или свой редирект с логированием) или через отдельного бота/сервис. В Telegram нет встроенной «статистики открытий» для произвольных сообщений; для каналов есть счётчик просмотров поста.
Минимальный учёт по рассылке: перед рассылкой сохраняете campaign_id, user_id, sent_at; при ошибке отправки — помечаете как failed. По этим данным можно строить отчёт «доставлено / не доставлено».
Итоги
Рассылки в боте работают лучше, когда есть сегментация и кнопки. Статистика помогает доводить контент до целевой аудитории и не перегружать всех подряд.