Как отправить сообщение через бота Telegram: sendMessage, разметка и кнопки
Чтобы отправить сообщение через бота Telegram, достаточно одного HTTP-запроса к методу sendMessage: https://api.telegram.org/bot<token>/sendMessage с параметрами chat_id (кому) и text (что). Ниже — готовые примеры на curl, Python и JavaScript, форматирование через parse_mode (HTML и MarkdownV2), inline-кнопки, отправка в группы и каналы и разбор ошибок, которые чаще всего возвращает Telegram Bot API.
Как отправить сообщение через бота: формат запроса
Любой метод Telegram Bot API вызывается по адресу https://api.telegram.org/bot<token>/ИМЯ_МЕТОДА. Обратите внимание: слово bot пишется слитно с токеном. Поддерживаются GET и POST, а параметры можно передать в query string, как application/x-www-form-urlencoded, application/json или multipart/form-data (последний нужен для загрузки файлов).
У sendMessage два обязательных параметра:
chat_id— числовой идентификатор чата или@usernameпубличного канала или супергруппы. Если id ещё неизвестен, посмотрите гайд как узнать chat id;text— от 1 до 4096 символов, считая после разбора разметки.
Ответ всегда приходит в JSON: при успехе — "ok": true и отправленное сообщение (объект Message) в поле result, при ошибке — "ok": false, error_code и description. И главное ограничение: бот не может написать пользователю первым. Человек должен сам открыть бота и нажать «Старт» (/start).
Отправка сообщения через curl
Самый быстрый способ проверить, что всё работает. Подставьте свой токен и chat id:
TOKEN="123456789:AAEexampleTokenReplaceWithYours"
curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
-H "Content-Type: application/json" \
-d '{"chat_id": 123456789, "text": "Привет! Это сообщение отправлено через Bot API"}'
Успешный ответ (сокращённо):
{
"ok": true,
"result": {
"message_id": 42,
"chat": {"id": 123456789, "first_name": "Иван", "type": "private"},
"date": 1793275200,
"text": "Привет! Это сообщение отправлено через Bot API"
}
}
Если параметров немного, можно обойтись без JSON — curl сам закодирует кириллицу и спецсимволы:
curl -s "https://api.telegram.org/bot$TOKEN/sendMessage" \
-d chat_id=123456789 \
--data-urlencode "text=Сборка #512 прошла успешно"
Пример на Python (requests)
import requests
TOKEN = "123456789:AAEexampleTokenReplaceWithYours"
API_URL = f"https://api.telegram.org/bot{TOKEN}"
def send_message(chat_id, text, **params):
payload = {"chat_id": chat_id, "text": text, **params}
resp = requests.post(f"{API_URL}/sendMessage", json=payload, timeout=10)
data = resp.json()
if not data["ok"]:
raise RuntimeError(f"{data['error_code']}: {data['description']}")
return data["result"]
msg = send_message(123456789, "Привет из Python!")
print("message_id:", msg["message_id"])
Функция возвращает объект Message: message_id пригодится, чтобы потом отредактировать или удалить сообщение. Дополнительные параметры передаются именованными аргументами, например send_message(chat_id, text, parse_mode="HTML").
Пример на JavaScript (fetch)
// Node.js 18+: fetch встроен. Запуск: BOT_TOKEN=... node send.mjs
const TOKEN = process.env.BOT_TOKEN ?? '123456789:AAEexampleTokenReplaceWithYours';
async function sendMessage(chatId, text, extra = {}) {
const res = await fetch(`https://api.telegram.org/bot${TOKEN}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: chatId, text, ...extra }),
});
const data = await res.json();
if (!data.ok) throw new Error(`${data.error_code}: ${data.description}`);
return data.result;
}
const msg = await sendMessage(123456789, 'Привет из JavaScript!');
console.log('message_id:', msg.message_id);
Этот код заработает и в браузере, но в продакшене так делать нельзя: токен во фронтенде увидит любой посетитель. Отправку держите на сервере, а токен — в переменных окружения.
parse_mode HTML: жирный текст, ссылки и код
Чтобы оформить текст, передайте "parse_mode": "HTML". Telegram понимает ограниченный набор тегов:
<b>/<strong>— жирный,<i>/<em>— курсив,<u>/<ins>— подчёркнутый,<s>/<strike>/<del>— зачёркнутый;<tg-spoiler>или<span class="tg-spoiler">— спойлер;<a href="…">— ссылка, в том числеtg://user?id=…для упоминания пользователя;<code>,<pre>и<pre><code class="language-python">— код, в последнем случае с подсветкой;<blockquote>и<blockquote expandable>— обычная и сворачиваемая цитата.
curl -s -X POST "https://api.telegram.org/bot$TOKEN/sendMessage" \
-H "Content-Type: application/json" \
-d '{
"chat_id": 123456789,
"parse_mode": "HTML",
"text": "<b>Заказ №1024 оплачен</b>\nСумма: <code>1 990 ₽</code>\n<a href=\"https://example.com/orders/1024\">Открыть заказ</a>"
}'
Все символы <, > и &, которые не входят в тег, нужно заменить на <, > и &. Из именованных HTML-сущностей API понимает только эти три и ", плюс любые числовые. Пользовательский ввод экранируйте всегда:
import html
name = "<Иван & Ко>" # пришло от пользователя
text = f"Новый заказ от <b>{html.escape(name, quote=False)}</b>"
send_message(123456789, text, parse_mode="HTML")
MarkdownV2 в Telegram: синтаксис и экранирование
MarkdownV2 компактнее HTML: *жирный*, _курсив_, __подчёркнутый__, ~зачёркнутый~, ||спойлер||, `код`, [ссылка](https://example.com), а строки, начинающиеся с >, превращаются в цитату. Подвох — в экранировании: вне разметки каждый из символов _ * [ ] ( ) ~ ` > # + - = | { } . ! нужно предварять обратным слешем \, иначе API вернёт ошибку разбора. Сам \ тоже экранируется. Внутри `кода` и блоков ``` экранируются только ` и \, а внутри круглых скобок ссылки — ) и \.
import re
def escape_md2(text: str) -> str:
return re.sub(r"([_*\[\]()~`>#+\-=|{}.!\\])", r"\\\1", text)
price = "1.990 руб. (скидка -10%)"
send_message(123456789, f"*Итого:* {escape_md2(price)}", parse_mode="MarkdownV2")
# уйдёт текст: *Итого:* 1\.990 руб\. \(скидка \-10%\)
На JavaScript это одна строка:
const escapeMd2 = (s) => s.replace(/[_*[\]()~`>#+\-=|{}.!\\]/g, '\\$&');
Старый режим Markdown оставлен только для обратной совместимости: в нём нет подчёркивания, зачёркивания, спойлеров и цитат. Для новых ботов выбирайте HTML или MarkdownV2, а если текст приходит от пользователей, HTML обычно надёжнее — экранировать нужно всего три символа.
Inline-кнопки: reply_markup с url и callback_data
Кнопки под сообщением задаются параметром reply_markup с полем inline_keyboard — это массив рядов, а каждый ряд — массив кнопок. Кнопка с url открывает ссылку, кнопка с callback_data присылает боту апдейт callback_query.
{
"chat_id": 123456789,
"text": "Подтвердите заказ №1024",
"reply_markup": {
"inline_keyboard": [
[{"text": "Открыть сайт", "url": "https://example.com"}],
[
{"text": "Подтвердить", "callback_data": "confirm:1024"},
{"text": "Отменить", "callback_data": "cancel:1024"}
]
]
}
}
callback_data— от 1 до 64 байт, а не символов: буква кириллицы в UTF-8 занимает 2 байта. Кладите туда короткий идентификатор, а сами данные храните у себя.- На каждое нажатие отвечайте методом
answerCallbackQueryсcallback_query_idиз апдейта: пока ответа нет, клиент Telegram показывает на кнопке индикатор загрузки. - Если параметры уходят не JSON-телом, а через query string или form-data,
reply_markupпередаётся строкой с сериализованным JSON.
Как отправить сообщение в группу или канал
- Группа и супергруппа. Добавьте бота в чат и используйте id чата: у обычных групп он отрицательный, у супергрупп начинается с
-100, например-1001234567890. Privacy mode ограничивает только входящие сообщения и на отправку не влияет. - Канал. Бот должен быть администратором с правом публикации. В
chat_idподойдёт@usernameпубличного канала или числовой id вида-100…для приватного. - Тема форума. Добавьте параметр
message_thread_idс id темы. - Группу превратили в супергруппу. Старый id перестаёт работать: API вернёт ошибку 400, а новый id придёт в
parameters.migrate_to_chat_id— сохраните его.
curl -s "https://api.telegram.org/bot$TOKEN/sendMessage" \
-d chat_id=@my_channel \
--data-urlencode "text=Новый пост в канале"
Тихие сообщения, превью ссылок и ответы
{
"chat_id": 123456789,
"text": "Ночной отчёт готов: https://example.com/report",
"disable_notification": true,
"link_preview_options": {"is_disabled": true},
"protect_content": true,
"reply_parameters": {"message_id": 42}
}
disable_notification— сообщение придёт без звука;link_preview_options— настройки превью:is_disabledотключает его,urlзадаёт ссылку для превью,show_above_textставит превью над текстом;protect_content— запрет пересылки и сохранения;reply_parameters— ответ на конкретное сообщение по егоmessage_id.
Частые ошибки sendMessage и что с ними делать
| Ошибка | Причина | Что делать |
|---|---|---|
400 Bad Request: chat not found | Неверный chat_id, пользователь не запускал бота, бота нет в группе или канале | Проверьте id через getUpdates, добавьте бота в чат |
400 Bad Request: can't parse entities | Ошибка разметки: неэкранированный символ MarkdownV2 или незакрытый тег | Экранируйте текст, проверьте теги |
400 Bad Request: message is too long | Текст длиннее 4096 символов | Разбейте его на несколько сообщений |
401 Unauthorized | Неверный или отозванный токен | Проверьте токен через getMe |
403 Forbidden: bot was blocked by the user | Пользователь заблокировал бота | Исключите его из рассылки |
403 Forbidden: bot can't initiate conversation with a user | Пользователь ни разу не запускал бота | Попросите его нажать «Старт» |
429 Too Many Requests: retry after N | Превышен лимит частоты | Подождите retry_after секунд и повторите |
Так выглядит ответ с ошибкой 429:
{"ok": false, "error_code": 429, "description": "Too Many Requests: retry after 7", "parameters": {"retry_after": 7}}
Подробно о лимитах и о том, как делать рассылки без 429, — в гайде лимиты Telegram Bot API.
Попробуйте sendMessage без кода
- Откройте Bot API Tester на форме sendMessage.
- Вставьте токен бота. Если токена ещё нет, поможет гайд как получить токен бота.
- Заполните
chat_idиtext, при желании выберитеparse_modeи добавьтеreply_markup. - Нажмите Ctrl+Enter: в ответе появится
message_idили текст ошибки.
Полное описание всех параметров метода — на странице sendMessage.
Частые вопросы
Как отправить сообщение через бота телеграм без библиотек?
Отправьте HTTP-запрос на https://api.telegram.org/bot<token>/sendMessage с параметрами chat_id и text. Подойдёт curl, requests в Python или fetch в JavaScript — SDK для этого не нужен.
Почему бот не может написать пользователю первым?
Так устроен Telegram: бот не может начать диалог сам. Пользователь должен открыть бота и нажать «Старт» — до этого sendMessage будет возвращать ошибку 403.
Какие символы нужно экранировать в MarkdownV2?
Вне разметки — _ * [ ] ( ) ~ ` > # + - = | { } . ! и сам обратный слеш: перед каждым из них ставится \. Иначе Telegram вернёт ошибку 400 о том, что не может разобрать сущности.
Как отправить сообщение в канал через бота?
Сделайте бота администратором канала с правом публикации и укажите в chat_id @username канала. Для приватного канала используйте числовой id вида -1001234567890.
Что выбрать для parse_mode: HTML или MarkdownV2?
Для текста от пользователей надёжнее HTML: экранировать нужно только <, > и &. MarkdownV2 компактнее, но требует экранировать 18 спецсимволов.
Что делать при ошибке 429 Too Many Requests?
Подождать столько секунд, сколько указано в parameters.retry_after, и повторить запрос. Чтобы не ловить 429, держите темп не выше 1 сообщения в секунду в один чат и около 30 сообщений в секунду суммарно.
Читайте также
Как создать бота в Телеграм: от @BotFather до первого сообщения
Как создать бота в Телеграм: регистрация в @BotFather, токен, проверка через getMe, первое сообщение на curl и Python, команды и описание бота.
Что нового в Telegram Bot API 10.0–10.3: rich-сообщения, эфемерные сообщения и гостевой режим
Что нового в Telegram Bot API 10.0–10.3: rich-сообщения, эфемерные сообщения, гостевой режим, заявки на вступление — с примерами и чек-листом миграции.
Лимиты Telegram Bot API: сообщения в секунду, ошибка 429 и размеры файлов
Все лимиты Telegram Bot API в одном месте: сообщения в секунду, ошибка 429 и retry_after, платные рассылки, размеры файлов, длина текста и подписи.
Токен бота Telegram: как получить, где найти, как проверить и отозвать
Как получить токен бота Телеграм в @BotFather, где взять токен уже созданного бота, как проверить его через getMe и что делать, если токен утёк.
Вебхук для Telegram-бота: настройка setWebhook, проверка и удаление
Как настроить вебхук Телеграм-бота: требования к HTTPS и портам, setWebhook с secret_token, проверка через getWebhookInfo, удаление и частые ошибки.
Как узнать chat id в Telegram: пользователь, группа, канал и тема форума
Как узнать chat id в Telegram через getUpdates: личный чат, группа, супергруппа, канал и тема форума. Форматы id с -100 и что делать с пустым result.
Тестирование Telegram Mini App: от браузера до отладки на телефоне
Тестирование Telegram Mini App по шагам: mock-режим в браузере, HTTPS-туннель для localhost, тестовая среда, DevTools на телефоне и проверка initData.