Telegram Bot API
🌐 中文

Telegram Bot API 发送消息教程:sendMessage 参数、格式、按钮与错误处理

· 9 分钟阅读

Telegram Bot API 发送消息只需要调用一个方法:sendMessage。向 https://api.telegram.org/bot<token>/sendMessage 发送请求,带上 chat_id(发给谁)和 text(发什么,1–4096 个字符),Telegram(电报)就会以机器人的身份把消息投递到对应的聊天。本文可以当作 sendMessage 的中文文档来使用:先给出 curl、Python、JavaScript 的可复制示例,再讲 HTML 与 MarkdownV2 格式、内联按钮、群组和频道、静音发送与链接预览,最后整理最常见的错误。

Telegram Bot API 发送消息的请求格式

所有 Bot API 方法都通过 HTTPS 调用,地址格式为 https://api.telegram.org/bot<token>/METHOD_NAME。注意 bot 与 Token 之间没有斜杠;方法名不区分大小写;所有请求都必须使用 UTF-8 编码。支持 GET 和 POST 两种方式,参数可以通过以下四种方式传递:

响应始终是 JSON:成功时为 "ok": true,结果在 result 中;失败时为 "ok": false,并带有 error_code 和 description,部分错误还会附带 parameters(如 retry_after、migrate_to_chat_id),方便程序自动处理。

sendMessage 参数中文说明

参数类型说明
chat_idInteger 或 String必填。目标聊天的数字 ID,或 @channelusername 形式的用户名
textString必填。消息正文,解析格式后为 1–4096 个字符
parse_modeString格式解析模式:HTML、MarkdownV2 或旧版 Markdown
entitiesArray直接指定格式实体,可代替 parse_mode
reply_markupObject内联键盘、自定义回复键盘、移除键盘或强制回复
link_preview_optionsObject链接预览的生成选项
disable_notificationBoolean静音发送,用户会收到无声通知
protect_contentBoolean禁止转发和保存消息内容
reply_parametersObject以回复的形式引用某条消息
message_thread_idInteger发送到论坛的指定话题

还没有 Token 或 chat_id?请先阅读 Telegram Bot Token 获取教程和 Telegram chat id 获取教程。另外请记住:机器人不能主动发起对话,用户必须先打开机器人并点击 Start。

用 curl 发送消息

这是最快的验证方式。GET 请求中的中文需要 URL 编码,用 -G 配合 --data-urlencode 可以让 curl 自动处理:

curl -G "https://api.telegram.org/bot123456789:AAEexampleTokenReplaceWithYours/sendMessage" \
  --data-urlencode "chat_id=123456789" \
  --data-urlencode "text=你好,这是一条来自 curl 的消息"

更推荐用 POST 发送 JSON,按钮、预览选项等嵌套参数写起来更方便:

curl -X POST "https://api.telegram.org/bot123456789:AAEexampleTokenReplaceWithYours/sendMessage" \
  -H "Content-Type: application/json" \
  -d '{"chat_id": 123456789, "text": "你好,这是一条来自 curl 的消息"}'

成功响应(节选):

{
  "ok": true,
  "result": {
    "message_id": 42,
    "chat": {"id": 123456789, "first_name": "Alex", "type": "private"},
    "date": 1793266200,
    "text": "你好,这是一条来自 curl 的消息"
  }
}

记下返回的 message_id,之后可以用它编辑或删除这条消息。

用 Python 发送消息

使用 requests 库,封装成一个出错时抛出异常的函数:

import requests

TOKEN = "123456789:AAEexampleTokenReplaceWithYours"
API = f"https://api.telegram.org/bot{TOKEN}"

def send_message(chat_id, text, **params):
    payload = {"chat_id": chat_id, "text": text, **params}
    data = requests.post(f"{API}/sendMessage", json=payload, timeout=10).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"])

用 JavaScript(fetch)发送消息

适用于 Node.js 18 及以上版本(以 ES 模块运行,支持顶层 await),或任何提供 fetch 的运行环境:

const 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);

这段代码应该运行在服务器端。不要把 Token 写进网页前端,任何人都能在浏览器里看到它。

parse_mode:HTML 格式

设置 "parse_mode": "HTML" 后,可以使用以下标签:

除了标签之外,文本中所有的 <、>、& 都必须写成 &lt;、&gt;、&amp;。插入用户输入之类的动态内容前,一定要先转义:

import html

name = html.escape("Tom & Jerry <3", quote=False)  # 结果:Tom &amp; Jerry &lt;3
send_message(
    123456789,
    f"<b>订单 #1024</b>\n收件人:{name}\n状态:<i>已发货</i>\n"
    '<a href="https://example.com/track/1024">查看物流</a>',
    parse_mode="HTML",
)

parse_mode:MarkdownV2 格式

MarkdownV2 的常用语法:*粗体*、_斜体_、__下划线__、~删除线~、||剧透||、[链接文字](https://example.com)、`行内代码`,三个反引号包裹代码块,> 开头表示引用。

最容易出错的是转义规则。在格式标记之外,下面这些字符都必须在前面加反斜杠 \:

_ * [ ] ( ) ~ ` > # + - = | { } . !

反斜杠本身也要转义。在 pre 和 code 内部,只需转义 ` 和 \;在链接的 (…) 部分,只需转义 ) 和 \。版本号里的点(如 v1.2)、日期里的横线、句末的感叹号,都是导致 400 Bad Request: can't parse entities 的常见原因。处理动态文本时用一个函数统一转义:

import re

def escape_md2(text):
    return re.sub(r"([_*\[\]()~`>#+\-=|{}.!\\])", r"\\\1", text)

send_message(123456789, f"*版本 {escape_md2('v1.2-beta')}* 已发布\\!",
             parse_mode="MarkdownV2")
const escapeMd2 = (s) => s.replace(/[_*[\]()~`>#+\-=|{}.!\\]/g, "\\$&");

用 reply_markup 添加内联按钮

内联键盘是显示在消息下方的按钮,按“行”组织。url 按钮点击后打开链接;callback_data 按钮点击后,机器人会收到一个 callback_query 更新,其中带有这段数据:

curl -X POST "https://api.telegram.org/bot123456789:AAEexampleTokenReplaceWithYours/sendMessage" \
  -H "Content-Type: application/json" \
  -d '{
    "chat_id": 123456789,
    "text": "请选择:",
    "reply_markup": {"inline_keyboard": [[
      {"text": "打开网站", "url": "https://example.com"},
      {"text": "点我", "callback_data": "pressed"}
    ]]}
  }'

注意 callback_data 的长度限制是 1–64 字节,不是字符。一个汉字在 UTF-8 中占 3 个字节,所以最多只能放 21 个汉字,建议用简短的英文标识,例如 order:1024。用 JSON 发送时 reply_markup 是嵌套对象;用查询字符串或表单发送时,需要先把它序列化成 JSON 字符串。

用户点击回调按钮后,客户端会一直显示加载状态,直到机器人调用 answerCallbackQuery,所以即使不需要提示文字也要应答:

cq = update["callback_query"]
requests.post(f"{API}/answerCallbackQuery",
              json={"callback_query_id": cq["id"], "text": "已收到"}, timeout=10)

发送到群组、频道和话题

普通群组升级为超级群组后,ID 会发生变化。这时用旧 ID 发送会失败,错误响应中的 parameters.migrate_to_chat_id 就是新 ID,保存后重试即可。

静音发送、链接预览与回复消息

{
  "chat_id": 123456789,
  "text": "更新日志:https://example.com/changelog",
  "disable_notification": true,
  "protect_content": true,
  "link_preview_options": {"is_disabled": true},
  "reply_parameters": {"message_id": 42}
}

disable_notification 让用户收到无声通知,适合夜间推送;protect_content 禁止转发和保存。link_preview_options 取代了旧参数 disable_web_page_preview:用 is_disabled 关闭预览,或者用 url、prefer_small_media、prefer_large_media、show_above_text 调整预览的内容和位置。reply_parameters 中的 message_id 指定要回复的消息。

常见错误:400、403、429

请求失败时会返回 "ok": false,例如 {"ok": false, "error_code": 400, "description": "Bad Request: chat not found"}。

错误原因解决方法
400 Bad Request: chat not foundchat_id 错误、漏了负号或 -100 前缀;用户从未启动过机器人;机器人不在该群组或频道中用 getUpdates 重新确认 ID;请用户点击 Start;把机器人加入聊天
400 Bad Request: can't parse entitiesMarkdownV2 有字符没有转义,或 HTML 标签不合法转义文本;临时去掉 parse_mode 定位问题
401 UnauthorizedToken 无效或已被撤销用 getMe 检查 Token
403 Forbidden: bot was blocked by the user用户屏蔽了机器人停止向该用户发送,重试没有意义
429 Too Many Requests超过了频率限制等待 parameters.retry_after 秒后重试

官方建议的发送节奏是:同一聊天每秒不超过 1 条,同一群组每分钟不超过 20 条,群发总量约每秒 30 条。遇到 429 时的最简重试逻辑:

import time

def send_with_retry(chat_id, text, **params):
    while True:
        payload = {"chat_id": chat_id, "text": text, **params}
        r = requests.post(f"{API}/sendMessage", json=payload, timeout=10).json()
        if r["ok"]:
            return r["result"]
        if r["error_code"] != 429:
            raise RuntimeError(r["description"])
        time.sleep(r.get("parameters", {}).get("retry_after", 1))

如果要给大量用户群发,仅靠重试是不够的,应该用队列控制发送速度。

在浏览器中试用 sendMessage

  1. 打开 Bot API Tester 中的 sendMessage,粘贴你的 Token(只保存在浏览器的 localStorage 中,工具界面为英文)。
  2. 填写 chat_id 和 text,按需设置 parse_mode、reply_markup 等参数。
  3. 点击执行或按 Ctrl+Enter,在 JSON 查看器中检查返回结果。

完整的参数列表可以查看英文版的 sendMessage 方法参考,所有方法的 OpenAPI 描述见 Swagger 文档。如果你刚开始接触机器人开发,建议从 创建 Telegram 机器人教程读起。

常见问题

Telegram Bot API 怎么发送消息?

向 https://api.telegram.org/bot<token>/sendMessage 发送 GET 或 POST 请求,带上 chat_id 和 text 两个必填参数。成功时返回 "ok": true,result 中是发送出去的 Message 对象。

机器人能主动给任何用户发消息吗?

不能。机器人只能给已经和它互动过的用户发消息:用户必须先打开机器人并点击 Start(或者发过消息)。否则 sendMessage 会报错,常见的是 400 Bad Request: chat not found。

MarkdownV2 需要转义哪些字符?

在格式标记之外,_ * [ ] ( ) ~ ` > # + - = | { } . ! 这些字符都要在前面加反斜杠 \,反斜杠本身也需要转义。漏掉一个就会返回 400 错误。

parse_mode 选 HTML 还是 MarkdownV2?

处理用户输入等动态文本时,HTML 更省心:只需要把 <、>、& 转义为 &lt;、&gt;、&amp;。MarkdownV2 写起来简洁,但需要转义的字符很多,容易出错。

怎么用机器人往频道发消息?

先把机器人设为频道管理员并允许发布消息。公开频道的 chat_id 可以直接写 "@channelusername",私有频道则使用 -100 开头的数字 ID。

遇到 429 Too Many Requests 怎么办?

说明触发了频率限制。按响应中 parameters.retry_after 给出的秒数等待后再重试,并控制发送速度:同一聊天每秒不超过 1 条,同一群组每分钟不超过 20 条,群发总量约每秒 30 条以内。

Telegram 机器人教程:从零创建 Telegram 机器人并发送第一条消息

Telegram 机器人教程:在 @BotFather 中用 /newbot 创建机器人并获取 Token,用 getMe 验证,再通过 getUpdates 找到 chat_id,用 curl 和 Python 发出第一条消息,附常见问题排查。

Telegram Bot Token 怎么获取:获取、查看、验证和撤销机器人 Token

Telegram Bot Token 怎么获取?用 @BotFather 的 /newbot 获取新 Token,在 /mybots 中查看已有 Token,用 getMe 检查是否有效,泄露后及时撤销,并配合 chat_id 接入 n8n 等工具。

Telegram Bot Webhook 设置教程:用 setWebhook 配置 Webhook URL 和 secret_token

Telegram Bot API setWebhook 中文教程:Webhook URL 的 HTTPS 与端口要求、secret_token 请求头校验、用 getWebhookInfo 排错、用 deleteWebhook 切回轮询,以及 409 等常见错误的解决方法。

Telegram chat id 获取教程:查看用户、群组、频道和话题的聊天 ID

Telegram chat id 获取教程:用 getUpdates 查看私聊、群组、超级群组、频道和论坛话题的聊天 ID,讲清负数和 -100 前缀的含义,并排查 result 为空、409 Conflict 等常见问题,附 Python 示例。