Повідомлення
HTML і Markdown
Telegram поддерживает два режима разметки в text метода sendMessage (и других, где есть поле text): HTML и MarkdownV2. Режим выбирается параметром parse_mode. Если его не передать — текст отправится как есть, экранирования Telegram не делает.
HTML
HTML — самый простой режим для веб-разработчика. Поддерживаемые теги: <b>, <i>, <u>, <s>, <strike>, <del>, <code>, <pre>, <a href="...">, <tg-spoiler>. Переносы строк — обычный \n.
Главное правило: всегда экранировать пользовательский ввод. Иначе юзер с именем <script>...</script> сломает разметку, внедрит чужие ссылки или вообще уронит сообщение (Telegram вернёт 400 при невалидном HTML).
$safe = static fn(string $s): string =>
htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
telegramApi($token, 'sendMessage', [
'chat_id' => $chatId,
'parse_mode' => 'HTML',
'text' => "<b>Новая заявка</b>\n".
"Имя: {$safe($name)}\n".
"Комментарий: {$safe($comment)}",
]);Ссылка и спойлер:
telegramApi($token, 'sendMessage', [
'chat_id' => $chatId,
'parse_mode' => 'HTML',
'text' => '<a href="https://example.com/order/123">Заказ #123</a>\n'.(strlen($safe($name)) > 30 ? '<tg-spoiler>Все детали внутри</tg-spoiler>' : ''), 'chat_id' => $chatId,
'parse_mode' => 'HTML',
'text' => '<a href="https://example.com/order/123">Заказ #123</a>\n'.<tg-spoiler>Все детали внутри</tg-spoiler>'.',
]);MarkdownV2
MarkdownV2 мощнее (поддерживает цитаты, нумерованные/ненумерованные списки, экранирование спецсимволов через \), но капризный: любой неэкранированный символ _ * [ ] ( ) ~ ` > # + - = | { } . ! в тексте ломает парсинг. Для пользовательского ввода это значит — прогонять через escaper, который добавит обратный слэш перед каждым спецсимволом.
$escapeV2 = static fn(string $s): string =>
addcslashes($s, '_*[]()~`>#+-=|{}.!');
telegramApi($token, 'sendMessage', [
'chat_id' => $chatId,
'parse_mode' => 'MarkdownV2',
'text' => "*Заказ \#123*\n".
"Клиент: {$escapeV2($name)}\n".
"Сумма: {$escapeV2($sum)} руб.",
]);Что выбрать
- HTML — если в тексте идут пользовательские данные. Проще экранировать (
htmlspecialchars), меньше шансов ошибиться. - MarkdownV2 — если текст полностью под вашим контролем и нужны списки/цитаты/жирный код в одну строку.
- Без parse_mode — если сообщение состоит из одной строки без форматирования. Тогда
\nвсё равно работают как переносы.
Типичные ошибки
- Забыли экранировать поле из формы — приходит 400 Bad Request: can't parse entities.
- Вставили
<br>вместо\n— Telegram его не понимает, тег уедет в текст буквально. - Передали оба параметра:
parse_modeиentitiesодновременно — бот получит конфликт.
Для длинных текстов с кодом используйте <pre language="php">...</pre> — Telegram подсветит синтаксис.
Дальше: Фото, документы, media group.