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

Форматирование сообщений Telegram — это набор правил, по которым бот делает текст жирным, курсивным, моноширинным или ссылкой. Выразить его можно тремя способами: MarkdownV2, HTML и чистая строка вместе со списком диапазонов-сущностей. API принимает один способ на сообщение. Чаще всего боты берут MarkdownV2, и падает чаще всего именно он. Он резервирует восемнадцать символов, четыре из которых встречаются в обычных предложениях: точка, дефис, плюс и восклицательный знак. Предложение вида Заказ #123 готов! уже невалидно, и Telegram отвечает can’t parse entities вместо объяснения. Пока строили своих ботов, мы налетали на это так часто, что написали решение один раз и отдали его. Вставьте то, что у вас есть: обычный текст, Markdown или ответ языковой модели. Получите то, что API примет, в любом из трёх режимов.

  • Экранирование, которое знает, где находится. Зарезервированные символы экранируются по контексту, поэтому точки в pip install x==1.0 внутри код-блока выживают. Команда не приходит утыканной обратными слешами.
  • Разбивка, которая закрывает то, что открыла. После 4096 символов сообщение режется по границе за пределами всех сущностей. В следующей части форматирование открывается заново.
  • Ничего не покидает вкладку. Ни загрузок, ни аккаунта, и токен бота мы не спрашиваем. Форматированию текста он не нужен.

Что здесь есть, чего нет у остальных

Корректные смещения UTF-16
API считает позиции сущностей в кодовых единицах UTF-16. Python считает кодовые точки. Одно эмодзи сдвигает каждую следующую сущность на единицу, и сообщение отклоняется. Индекс строки в JavaScript — уже нужная единица, поэтому эти числа получаются верными без всякого шага конвертации.
Разбивка с учётом сущностей
Обычный slice(0, 4096) режет прямо посреди жирного фрагмента. API отвечает Can’t find end of Bold entity. Здесь точка разреза выбирается за пределами всех сущностей.
Расшифровка ошибок
Telegram сообщает о сбое смещением в байтах UTF-8. Оно не совпадает ни с чем, что показывает ваш редактор. Вставьте ошибку — получите строку, колонку и сам символ.

Все три вещи покрыты тестами, которые гоняются на каждом коммите и собраны из примеров в документации самого Telegram.

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

Вставьте текст или Markdown. Всё считается прямо в этой вкладке — ничего не загружается и не сохраняется.

201 / 4 096 символов
Похоже на вывод языковой модели

Ничего из документного синтаксиса ниже Telegram не принимает. Он преобразуется, а не экранируется, поэтому в сообщение не попадут лишние ## или |---|.

  • строка 1Заголовок ATX (#) — в Telegram заголовков нет
  • строка 3**Двойные звёздочки** — в MarkdownV2 нужна одна
  • строка 5Маркированный список — в Telegram нет разметки списков
  • строка 7Ссылка Markdown
  • строка 9Таблица Markdown — в текстовых сообщениях Telegram таблиц нет

Как это будет выглядеть

Отрисовано так же, как рисует клиент Telegram. Спойлеры скрыты, пока по ним не нажать. Ввод разбирается как Markdown.

Заказ #1284 собран! Привет, Ирина, заказ уехал сегодня. • Трек-номер: RU-8842-XZ • Доставка: 2-4 дня • Поддержка: написать нам Товар Кол-во ───── ────── Лампа 2 Отправьте СТОП, чтобы отписаться.
12:00

Что отправлять

Преобразовано из вашего Markdown.

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

*Заказ \#1284 собран\!*

Привет, *Ирина*, заказ уехал сегодня\.

• Трек\-номер: `RU-8842-XZ`
• Доставка: 2\-4 дня
• Поддержка: [написать нам](https://t.me/yourbot)

```
Товар  Кол-во
─────  ──────
Лампа  2
```

>Отправьте СТОП, чтобы отписаться\.

Как отправить

Строковый литерал экранирован под язык, так что переживёт вставку.

from telegram import Bot
from telegram.constants import ParseMode

bot = Bot(token=BOT_TOKEN)
await bot.send_message(
    chat_id="@yourchannel",
    text="*Заказ \\#1284 собран\\!*\n\nПривет, *Ирина*, заказ уехал сегодня\\.\n\n• Трек\\-номер: `RU-8842-XZ`\n• Доставка: 2\\-4 дня\n• Поддержка: [написать нам](https://t.me/yourbot)\n\n```\nТовар  Кол-во\n─────  ──────\nЛампа  2\n```\n\n>Отправьте СТОП, чтобы отписаться\\.",
    parse_mode=ParseMode.MARKDOWN_V2,
)

Разобрать ошибку API

Вставьте то, что ответил Telegram. Смещение в таких ошибках считается в байтах UTF-8 — поэтому оно никогда не совпадает с тем, что показывает редактор. Здесь оно переводится обратно в строку и столбец в выводе MarkdownV2 выше.

Преобразование и экранирование работают целиком в этой вкладке — на том же коде и тех же 137 тестах, на которых построены остальные наши инструменты. Ничего из набранного никуда не уходит.

Форматирование текста в приложении Telegram

Если вы пишете сообщение руками, а не отправляете его ботом, всё экранирование ниже вам не нужно. Выделите текст и выберите стиль. На телефоне нажмите и удерживайте, чтобы выделить, затем выберите во всплывающем меню. На десктопе выделите и вызовите меню правой кнопкой или используйте сочетание: Ctrl+B для жирного, Ctrl+Shift+M для моноширинного. Форматирование текста в Telegram — это восемь стилей и ни одним больше: жирный, курсив, подчёркнутый, зачёркнутый, спойлер, моноширинный, код-блок и цитата. Набор символами тоже работает: *bold*, _italic_, ~strikethrough~, ||spoiler|| и `code`.

Бот не может нажать кнопку на панели форматирования. Ради этого страница и существует. Он вынужден описывать форматирование внутри отправляемого сообщения — как MarkdownV2, как HTML или как список диапазонов-сущностей. У каждого варианта свои правила, с которыми человек, печатающий в приложении, не сталкивается никогда. И ещё одно, прямо: в Telegram нет выбора шрифта. Генераторы «красивых шрифтов», которые попадаются в поиске, подставляют похожие символы Unicode, а не меняют шрифт. Они ломают экранные читалки, часто не отображаются на других устройствах, а поиск читает результат как набор мусора. Эти восемь стилей — весь набор.

Таблицы, списки и код-блоки Markdown в Telegram

В обычном сообщении Telegram нет ни разметки списков, ни разметки таблиц. Значит, всё, что обещает их отправить, выбирает отображение за вас. Этот инструмент делает выбор явным. Маркеры превращаются в символ •. Нумерованные пункты сохраняют цифры и получают экранированную точку, которой требует MarkdownV2. Таблица становится одним блоком pre с выровненными колонками и линией под шапкой. Моноширинный шрифт — единственный способ сохранить выравнивание в мессенджере. Код-блоки — единственная конструкция, которая переносится напрямую: три обратных апострофа с необязательным именем языка, и приложение рисует это моноширинным шрифтом со своей кнопкой копирования. У rich-сообщений, появившихся в Bot API 10.1 11 июня 2026, наконец-то есть настоящие блоки списков и таблиц. Если цель — они, с ними работает конструктор rich-сообщений.

Почему наивное экранирование ломает код-блоки

Большинство конвертеров проходят строку один раз и ставят обратный слеш перед каждым зарезервированным символом. Для прозы это верно, для всего остального — нет. Правила MarkdownV2 меняются в зависимости от того, где вы находитесь. Внутри блока code или pre особенные только обратный апостроф и обратный слеш. Внутри скобочного адреса ссылки — только закрывающая скобка и обратный слеш. Проэкранируйте код-блок по правилам прозы, и ваш пользователь получит pip install python\-telegram\-bot==21\.0 — команду, которая после копирования уже не работает. Этот инструмент сначала разбирает сообщение на диапазоны, а потом решает про экранирование каждого символа по диапазону, который его охватывает. Так вопрос превращается из догадки в арифметику.

Как отправить ответ языковой модели в чат

Связка модели с ботом стала обычным делом, и вместе с ней пришла проблема форматирования, которой раньше не было. Модели отвечают полноценным GitHub-flavoured Markdown: заголовки второго уровня, вложенные списки, таблицы, горизонтальные линии, иногда картинка. В текстовом сообщении Telegram не поддерживает ничего из этого. Экранировать — неверный инстинкт. Сообщение станет валидным, а \#\# и \|---\| останутся видны в чате. Конвертировать — верный. Заголовок становится жирной строкой. Маркеры становятся •, нумерованный список сохраняет номера, а таблица превращается в моноширинный блок с выровненными колонками, чтобы она по-прежнему выравнивалась. Горизонтальная линия удаляется, потому что сопоставить её не с чем. Инструмент распознаёт эту форму при вставке и прямо об этом говорит.

Режим, который не может упасть на разборе

Если сообщения регулярно отклоняются, а причина каждый раз новая, перестаньте экранировать и отправляйте text плюс entities. Текст едет ровно таким, каким написан, а форматирование описано рядом списком диапазонов. Шага разбора, на котором что-то ломается, просто нет. Единственная опасность — единица измерения. Диапазоны считаются в кодовых единицах UTF-16, и язык, который меряет строки иначе, выдаст числа, выглядящие правильно и попадающие не туда. Это самая частая ошибка в самописном коде с entities, и проявляется она только когда кто-нибудь пришлёт эмодзи.

Форматирование сообщений Telegram — вопросы

Как форматировать текст в Telegram?
В приложении выделите текст и выберите стиль. На телефоне нажмите и удерживайте, чтобы выделить, затем выберите во всплывающем меню: «Жирный», «Курсив», «Моноширинный», «Зачёркнутый», «Подчёркнутый» или «Спойлер». На десктопе выделите и вызовите меню правой кнопкой либо используйте сочетание: Ctrl+B для жирного, Ctrl+Shift+M для моноширинного. Набор символами тоже работает: *жирный*, _курсив_, ~зачёркнутый~, ||спойлер|| и `код`. С ботом всё иначе. Он не может нажать кнопку на панели, поэтому отправляет форматирование как MarkdownV2, HTML или entities. Именно это и делает инструмент на этой странице.
Как изменить шрифт в Telegram?
В Telegram нет выбора шрифта для сообщений. Инструменты «красивых шрифтов», которые попадаются в выдаче, шрифт не меняют вообще: они подставляют похожие символы Unicode, а такие символы ломают экранные читалки и часто не отображаются на других устройствах. Что Telegram действительно даёт, так это фиксированный набор стилей: жирный, курсив, подчёркнутый, зачёркнутый, спойлер, моноширинный, код-блок и цитата. Они применяются к выделенному фрагменту через меню. Это тот же набор, который бот может отправить через API.
Что такое MarkdownV2 в Telegram?
MarkdownV2 — второй и актуальный режим разбора Markdown в Bot API, он передаётся в параметре parse_mode при отправке сообщения. Он заменил старый режим Markdown, который не умел подчёркивание, зачёркивание, спойлеры и цитаты и не допускал вложенности. Плата за эти возможности — экранирование. MarkdownV2 резервирует восемнадцать символов, каждый из которых требует обратного слеша, а внутри код-блоков и адресов ссылок правила меняются. Это экранирование инструмент и берёт на себя.
Как использовать ``` в Telegram?
Три обратных апострофа открывают и закрывают код-блок, а после открывающей тройки можно указать язык: ```python на отдельной строке, затем код, затем ``` на отдельной строке. В приложении блок рисуется моноширинным шрифтом и с кнопкой копирования. Спотыкаются обычно на двух вещах. Внутри блока обратный апостроф и обратный слеш всё равно нужно экранировать. А всё остальное трогать нельзя: конвертер, который экранирует внутри кода точки и дефисы, отдаёт вашему читателю команду, которая больше не запускается. Для короткого фрагмента внутри предложения используйте одиночные апострофы — получится `код` в строке.
Поддерживает ли Telegram таблицы и списки Markdown?
В обычном сообщении — нет. Разметки списков и разметки таблиц там не существует, поэтому конвертер вынужден выбирать, как их нарисовать. Маркеры превращаются в символ •, нумерованные пункты сохраняют цифры, а таблица становится моноширинным блоком с выровненными колонками. Только так выравнивание колонок переживает отправку в мессенджер. Bot API 10.1 от 11 июня 2026 изменил это для rich-сообщений: у них есть настоящие блоки списков и таблиц. Конструктор rich-сообщений на этом сайте работает именно с ними.
Какие символы нужно экранировать в MarkdownV2?
Восемнадцать штук: _ * [ ] ( ) ~ ` > # + - = | { } . ! — перед каждым нужен обратный слеш. Четыре из них подводят чаще всего: точка, дефис, плюс и восклицательный знак. Они встречаются в обычных предложениях. «Заказ #123 готов!» — это уже невалидный MarkdownV2, и API отвечает Bad Request: can’t parse entities. Но правила зависят от контекста. Внутри блока code или pre экранируются только обратный апостроф и обратный слеш. Внутри скобочной части ссылки — только закрывающая скобка и обратный слеш. Поэтому одна замена по всему сообщению портит код-блоки: она экранирует точки и дефисы, которые должны были остаться как есть.
Почему бот отвечает «can’t parse entities»?
Почти всегда одна из трёх причин. Зарезервированный символ остался неэкранированным, и Telegram начал читать разметку там, где вы имели в виду текст. Маркер открыли и не закрыли — тогда приходит «Can’t find end of Bold entity». Или сообщение обрезали на 4096 символах прямо посреди сущности, и закрывающий маркер уехал в часть, которая так и не отправилась. Вставьте ошибку в декодер выше вместе со своим выводом. Смещение, которое сообщает Telegram, считается в байтах UTF-8, поэтому оно никогда не совпадает с тем, что показывает редактор. Декодер переводит его в строку и колонку, с которыми уже можно работать.
Как отправить в Telegram ответ ChatGPT или Claude?
Не экранировать, а конвертировать. Языковые модели отвечают в GitHub-flavoured Markdown: заголовки через ##, маркированные списки, таблицы, горизонтальные линии. В текстовом сообщении Telegram не поддерживает ничего из этого. Экранирование оставит решётки и вертикальные черты видимыми в чате. Конвертация переводит каждую конструкцию в то, что у Telegram есть. Заголовки становятся жирными строками, маркеры — символом •, нумерованные списки сохраняют номера, а таблицы превращаются в моноширинный блок с выровненными колонками. Горизонтальные линии выбрасываются, потому что сопоставить их не с чем. Вставьте ответ выше — инструмент распознает эту форму и сконвертирует её.
Чем отличаются MarkdownV2, HTML и entities?
Это три способа описать одно и то же форматирование. MarkdownV2 используют чаще всего, и правил экранирования у него больше всех. В режиме HTML экранируются всего три символа — <, > и &, — поэтому его проще генерировать из шаблона. Режим text + entities отправляет чистый текст нетронутым и рядом список диапазонов. Правил экранирования там нет вообще, так что упасть на разборе он не может. Подвох в другом: диапазоны считаются в кодовых единицах UTF-16, и именно на этом ломается большинство самописных реализаций. Если сообщения регулярно отклоняются, а причину найти не удаётся, entities — тот режим, который закрывает проблему.
Почему смещения entity сбиваются, если в сообщении есть эмодзи?
Потому что Bot API считает смещения в кодовых единицах UTF-16, а ваш язык, скорее всего, нет. В Python len() считает кодовые точки, поэтому эмодзи за пределами базовой многоязычной плоскости — а это почти все эмодзи — там равно 1, а для Telegram равно 2. Каждая сущность после этого эмодзи уезжает на единицу. Форматирование ложится не на те символы, либо API отклоняет сообщение целиком. В JavaScript индексы строк уже в UTF-16, поэтому смещения, которые выдаёт этот инструмент, корректны как есть. Копируйте их. Не пересчитывайте на другой стороне.
Какой длины может быть сообщение в Telegram?
4096 символов для текстового сообщения и 1024 для подписи к медиа, причём считается длина после разбора сущностей. То есть текст, который видит читатель, а не экранированный исходник, который вы отправляете. Разница важна: экранирование способно почти удвоить исходник. 200 точек превращаются в 400 символов MarkdownV2, но считаются всё равно как 200. Rich-сообщения из Bot API 10.1 поднимают потолок до 32 768. А когда сообщение всё-таки надо разбить, разрез должен попасть за пределы всех форматирующих сущностей, иначе часть уедет с незакрытым маркером.
Мой текст куда-нибудь загружается?
Нет. Разбор, экранирование, конвертация и предпросмотр выполняются в этой вкладке браузера, и страница не делает ни одного сетевого запроса с вашим содержимым. Это архитектурное решение, а не обещание. В форматтер вставляют реальные тексты рассылок и реальные имена клиентов, и ничему из этого незачем оказываться на сервере.
Вы когда-нибудь просите токен бота?
Никогда — ни здесь, ни на других страницах. Форматирование это чистое преобразование текста. Для работы ему не нужны никакие доступы, так что запрашивать токен значило бы собирать то, что нам незачем. Если инструмент форматирования просит токен бота, это повод присмотреться к нему внимательнее. Токен — полный контроль над вашим ботом.

Собираете ссылки, которые отправляет бот? Генератор ссылок строит пары t.me и tg:// со start-payload. Работаете с блоками Bot API 10.1? Ими занимается конструктор rich-сообщений. Весь набор перечислен в каталоге инструментов.