Главная/Статьи/Telegram-уведомления из Laravel

Telegram-уведомления из Laravel

Отправляем уведомления в Telegram: создание бота, Laravel Notifications, форматирование сообщений, кнопки, группы. Production-ready код.

ДМ
Дмитрий Мещеряков
📅 12 июня 2026 г.📖 5 мин чтения

Telegram как канал уведомлений в Laravel встраивается штатно: система нотификаций рассчитана на несколько каналов, и Telegram становится одним из них наравне с почтой. Это удобнее собственного HTTP-клиента и, что важнее, даёт очередь, повторы и единый формат из коробки.

Разберём настройку и три вещи, которые обычно упускают: экранирование текста, поведение при отказе и то, что делать с пользователями, не начавшими диалог с ботом.

Создание Telegram-бота

  1. Откройте BotFather в Telegram
  2. Отправьте /newbot
  3. Введите имя и username бота
  4. Получите токен

Добавьте в .env:

text
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrsTUVwxyz
TELEGRAM_ADMIN_CHAT_ID=987654321
💡 Совет

Чтобы узнать chat_id, отправьте боту сообщение, затем откройте api.telegram.org/botTOKEN/getUpdates и найдите chat.id в ответе.

Установка пакета

bash
composer require laravel-notification-channels/telegram

Настройте в config/services.php:

text
'telegram-bot-api' => [
    'token' => env('TELEGRAM_BOT_TOKEN'),
],

Простая отправка

text
TelegramMessage::create()
    ->to(config('services.telegram.admin_chat_id'))
    ->content('Новый заказ #123!')
    ->send();

Notification класс

Создайте notification:

bash
php artisan make:notification OrderCreatedNotification

Пример класса:

text
class OrderCreatedNotification extends Notification
{
    public function __construct(
        public Order $order
    ) {}
    public function via($notifiable): array
    {
        return [TelegramChannel::class];
    }
    public function toTelegram($notifiable): TelegramMessage
    {
        $url = route('admin.orders.show', $this->order);
        return TelegramMessage::create()
            ->to($notifiable->telegram_chat_id)
            ->content("Новый заказ #{$this->order->id}\n"
                . "Клиент: {$this->order->user->name}\n"
                . "Сумма: {$this->order->total} руб."
            )
            ->button('Открыть заказ', $url);
    }
}

Отправка уведомления

Конкретному пользователю:

text
$admin = User::where('role', 'admin')->first();
$admin->notify(new OrderCreatedNotification($order));

On-demand (без модели):

text
Notification::route('telegram', config('services.telegram.admin_chat_id'))
    ->notify(new OrderCreatedNotification($order));

Форматирование сообщений

⚠️ Важно

Текст с разметкой нужно экранировать. В режимах Markdown и HTML символы _, *, [, < в тексте интерпретируются как разметка. Имя клиента вида Иван_Петров или название товара с угловой скобкой ломают сообщение — Telegram вернёт ошибку разбора и уведомление не уйдёт вовсе.

Это не гипотетический случай: любые данные, пришедшие от пользователя (имя, комментарий к заказу, название товара), рано или поздно содержат такой символ. Экранируйте подставляемые значения либо не используйте разметку там, где она не нужна.

Поддерживается Markdown:

text
TelegramMessage::create()
    ->content("*Жирный текст*\n"
        . "_Курсив_\n"
        . "`Моноширинный`\n"
        . "[Ссылка](https://example.com)"
    );

Кнопки

Inline-кнопки:

text
TelegramMessage::create()
    ->content('Выберите действие:')
    ->button('Подтвердить', route('orders.confirm', $order))
    ->button('Отменить', route('orders.cancel', $order));

Несколько рядов кнопок:

text
TelegramMessage::create()
    ->content('Выберите категорию:')
    ->button('Электроника', '/category/electronics')
    ->button('Одежда', '/category/clothes')
    ->button('Все товары', '/catalog', true)  // true = новый ряд
    ->button('Корзина', '/cart', true);

Сервисный класс

Для централизации уведомлений создайте TelegramNotifier:

text
class TelegramNotifier
{
    private string $adminChatId;
    public function __construct()
    {
        $this->adminChatId = config('services.telegram.admin_chat_id');
    }
    public function orderCreated(Order $order): void
    {
        $this->send(
            "Новый заказ #{$order->id}\n"
            . "Клиент: {$order->user->name}\n"
            . "Сумма: " . $this->formatMoney($order->total),
            route('admin.orders.show', $order)
        );
    }
    public function orderPaid(Order $order): void
    {
        $this->send(
            "Заказ #{$order->id} оплачен\n"
            . "Сумма: " . $this->formatMoney($order->total)
        );
    }
    public function errorAlert(string $message): void
    {
        $this->send("Ошибка на сайте\n\n" . $message);
    }
    private function send(string $content, string $url = null): void
    {
        $message = TelegramMessage::create()
            ->to($this->adminChatId)
            ->content($content);
        if ($url) {
            $message->button('Открыть', $url);
        }
        try {
            $message->send();
        } catch (Exception $e) {
            logger()->error('Telegram notification failed');
        }
    }
    private function formatMoney(int $cents): string
    {
        return number_format($cents / 100, 0, ',', ' ') . ' руб.';
    }
}

Использование:

text
app(TelegramNotifier::class)->orderCreated($order);

Отправка в очередь

Добавьте интерфейс ShouldQueue:

text
class OrderCreatedNotification extends Notification implements ShouldQueue
{
    use Queueable;
    public string $queue = 'notifications';
}
⚠️ Важно

При настройке webhook проверяйте, что запрос пришёл от Telegram. Используйте secret token при регистрации webhook.

Что учесть в продакшене

Пользователь должен сам начать диалог с ботом. Telegram не позволяет боту написать первым: пока человек не нажал «Старт», отправка вернёт ошибку. Для уведомлений сотрудникам это решается один раз при подключении, для клиентов — превращается в отдельный сценарий подключения, и его нужно продумать до того, как обещать заказчику уведомления в Telegram.

Отказ должен быть заметен, но не критичен. Клиент заблокировал бота, токен отозван, Telegram недоступен — во всех случаях бизнес-операция (заказ, регистрация) обязана завершиться успешно. Отсюда: отправка только через очередь, обработка ошибки в failed(), и запасной канал для критичных уведомлений. Уведомление, ушедшее только в Telegram и не доставленное, равносильно неотправленному.

Ограничения частоты у Telegram реальны. Примерно 30 сообщений в секунду суммарно и заметно меньше в один и тот же чат. Массовая рассылка по базе клиентов упрётся в это ограничение, и без задержек между отправками бот получит временную блокировку. Для рассылок — отдельная очередь с ограничением частоты, а не общая.

Итоги

МетодНазначение
TelegramMessage::create()Быстрая отправка
Notification классСтруктурированные уведомления
button()Inline-кнопка с URL
WebhookОбработка ответов от бота

Чек-лист:

  1. Токен в .env, не в репозитории. При утечке — /revoke у BotFather.
  2. Отправка только через очередь с ShouldQueue: внешний сервис не должен влиять на скорость и успешность основной операции.
  3. Ошибки обрабатываются в failed(), а не теряются. Отдельно стоит различать «пользователь заблокировал бота» (нужно отключить канал для этого пользователя) и «Telegram недоступен» (нужен повтор).
  4. Подставляемые значения экранируются, если используется разметка.
  5. Есть запасной канал для критичных уведомлений.
  6. Для рассылок — отдельная очередь с ограничением частоты.
💡 Совет

Если бот должен ещё и принимать сообщения, а не только отправлять, — проверяйте secret_token вебхука. Без этого адрес обработчика становится единственной защитой, а он не секрет: попадает в логи, в историю команд и легко подбирается.

🚀

Хотите такое же решение?

Настрою окружение под ваш проект, учту специфику инфраструктуры и обучу команду.

Обсудить проект →
Бесплатная консультация · Ответ в течение дня

Комментарии

Система комментариев скоро будет подключена. А пока вы можете написать мне в Telegram или на email.