Сообщения
sendMessage
Практическое руководство по sendMessage: отправка текста, HTML-разметка, экранирование, работа с chat_id и обработка ошибок API на PHP с cURL.
sendMessage — основной метод Bot API для отправки текстового сообщения. В этой главе разберём обязательные параметры, безопасную работу с HTML-разметкой, типичные ошибки и то, как проверить ответ API в PHP.
Сигнатура метода и обязательные поля
Метод принимает chat_id (цель доставки) и text (содержимое до 4096 символов). Все остальные параметры опциональны: parse_mode, disable_web_page_preview, reply_markup и др.
Используем функцию telegramApi(), которую мы сделали в главе Первый запрос: getMe. Здесь только вызываем её — реализацию не копируем.
<?php
// reminder: telegramApi() из главы first-request
// function telegramApi(string $token, string $method, array $params = []): array { ... }
$token = getenv('TELEGRAM_BOT_TOKEN') ?: exit('TELEGRAM_BOT_TOKEN not set');
$chatId = 123456789; // замените на реальный chat_id
$result = telegramApi($token, 'sendMessage', [
'chat_id' => $chatId,
'text' => 'Привет! Это тестовое сообщение.',
]);
// Как посмотреть результат в терминале:
print_r($result);
// или для красивого JSON:
echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
Пример успешного ответа API
{
"message_id": 42,
"date": 1725000000,
"chat": {
"id": 123456789,
"type": "private",
"first_name": "Ivan",
"username": "ivan_test"
},
"text": "Привет! Это тестовое сообщение."
}
Что смотреть: message_id — уникальный идентификатор отправленного сообщения (нужен для editMessageText, deleteMessage); date — Unix-время отправки; chat — объект чата, подтверждающий доставку. Если поле ok в обёртке равно true — сообщение ушло в очередь Telegram.
HTML parse_mode и экранирование
Telegram не экранирует текст автоматически. Передача пользовательского ввода без экранирования в режиме HTML ломает разметку и открывает вектор для инъекций ссылок/тегов. Всегда используйте htmlspecialchars с флагами ENT_QUOTES | ENT_SUBSTITUTE и кодировкой UTF-8.
Используем функцию telegramApi() из главы Первый запрос: getMe.
<?php
$safe = static fn(string $s): string =
htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$name = $_POST['name'] ?? 'Аноним';
$email = $_POST['email'] ?? 'не указан';
$result = telegramApi($token, 'sendMessage', [
'chat_id' => $chatId,
'parse_mode' => 'HTML',
'text' => "<b>Новая заявка</b>\n"
. "Имя: {$safe($name)}\n"
. "Email: {$safe($email)}",
]);
echo "OK, message_id: {$result['message_id']}\n";
Поддерживаемые HTML-теги: <b>, <i>, <u>, <s>, <code>, <pre>, <a href="...">, <tg-spoiler>. Перенос строки — обычный \n. Подробнее о разметке и MarkdownV2 — в следующей главе.
Параметр chat_id: откуда брать и ограничения
- Личный чат:
user_id(число), который приходит вmessage.chat.idапдейта. Бот не может написать пользователю первым, если тот не нажал /start или не писал боту. - Группа/супергруппа: отрицательный
chat_id(например,-1001234567890). Бот должен быть участником. - Канал:
@channelusername(публичный) или числовойchat_id(приватный). Бот должен быть администратором канала.
Получить chat_id можно, выведя $update['message']['chat']['id'] в обработчике апдейтов (см. главу getUpdates и update_id).
Типичные ошибки и как их обрабатывать
- chat not found — неверный chat_id или бот не в чате. Проверить ID, добавить бота в группу/канал.
- bot was blocked by the user — пользователь заблокировал бота. Удалить chat_id из рассылки, не спамить.
- Too Many Requests: retry later (HTTP 429) — превышен лимит (30 msg/sec на чат, 20 msg/min в группу). Прочитать заголовок
Retry-After, поставить в очередь, повторить через указанное время. - Message is too long — текст > 4096 символов. Разбить на части или отправить как документ (
sendDocument). - Bad Request: can't parse entities — невалидный HTML/Markdown. Экранировать ввод, проверять закрывающие теги.
Используем функцию telegramApi() из главы Первый запрос: getMe.
<?php
try {
$result = telegramApi($token, 'sendMessage', [
'chat_id' => $chatId,
'text' => $longText,
]);
echo "OK, message_id: {$result['message_id']}\n";
} catch (RuntimeException $e) {
// Логируем для отладки
error_log('sendMessage failed: ' . $e->getMessage());
// Если 429 — можно извлечь Retry-After из заголовков (нужно расширить telegramApi)
// Если chat not found — пометить чат как неактивный в БД
}
Полезные опциональные параметры
disable_web_page_preview(bool) — отключает превью ссылок в сообщении.disable_notification(bool) — отправляет без звука (silent message).reply_to_message_id(int) — делает сообщение ответом на конкретное.reply_markup— клавиатуры (inline/reply/force_reply), разбираются в следующих главах.