Golang 实现 Telegram Bot 发送消息到指定话题(Topic)

485 阅读5分钟

前言

Telegram 在超级群组(Supergroup)中引入了 Topics(话题) 功能,使得群组内的讨论更加有条理。每个话题都有一个唯一的 ID,我们可以使用 Golang 通过 Telegram Bot API 发送消息到特定的话题。

这个功能在以下场景特别有用:

  • 自动化运维:将不同服务的监控告警发送到对应的话题中
  • 项目管理:自动将 CI/CD 状态、代码提交信息发送到特定话题
  • 社区管理:根据内容类型自动分类消息到不同话题

本文将介绍如何使用 gopkg.in/telebot.v3 库,结合 Telegram Bot API 发送消息到指定的 Topic,并提供完整的示例代码,帮助你快速实现该功能。


1. 前提条件

在开始之前,请确保你已经具备以下条件:

  • Telegram 机器人:已创建 Telegram 机器人(通过 BotFather 获取 Bot Token)。
  • 超级群组(Supergroup):开启Topic的群组。
  • 获取群组 ID 和话题 ID:你需要知道群组的 chat IDmessage_thread_id(即话题 ID)。
  • Golang 开发环境:已安装 Golang。

2. 安装依赖

我们将使用 telebot 库来与 Telegram 交互。安装它的方法如下:

 go get gopkg.in/telebot.v3

3. 获取群组 ID 和 Topic ID

在 Telegram 超级群组中,每个 Topic 都有一个唯一的 message_thread_id。获取 message_thread_id 的方法如下:

方式 1: 在Share link中获取

  1. 进入 Telegram 群组中,选中一个Topic,点击Channel名字,进入Info页面
  2. 在Info页面上有share link, 类似:https://t.me/1234567890/1
  3. share link的格式是这样的: https://t.me/chatId/topicId (Group的chatId需要在前面加上-100, 比如上面的chatId, 针对group就是: -1001234567890), 1是topicId

方式 2:从消息的share link中获取

  1. 进入 Telegram 群组,找到目标话题。
  2. 发送一条消息。
  3. 右键(电脑)或者长按(手机)发出的消息,选择 Copy Message Link, Message Link的格式类似 share link,只是多了messageId, 格式是这样的:https://t.me/chatId/topicId/messageId, chatId类似也需要加上 -100

方式 3:代码获取

你也可以使用 Telegram Bot 监听群组消息并自动获取 chat_idmessage_thread_id,需要设置Bot为管理员,这样才可以收到消息,这里获取到的chatId已经包含了-100,代码示例如下:

bot.Handle(telebot.OnText, func(c telebot.Context) error {
	fmt.Printf("Message: %s, Chat ID: %d, Thread ID: %d\n", c.Text(), msg.Chat.ID, msg.ThreadID)
	return nil
})

4. 发送消息到指定话题

以下是完整的 Golang 代码示例,展示如何使用 telebot 发送消息到指定话题。

代码示例

package main

import (
    "flag"
    "fmt"
    "time"

    "gopkg.in/telebot.v3"
)

func main() {
    // 定义命令行参数
    botToken := flag.String("token", "", "Telegram Bot Token")
    chatID := flag.Int64("chat", 0, "Chat ID (supergroup ID, 需要带-100前缀)")
    topicID := flag.Int("topic", 0, "Topic message thread ID (可选,General话题不需要指定)")
    messageText := flag.String("message", "Hello, Topic!", "要发送的消息内容")

    flag.Parse()

    // 验证必需的参数
    if *botToken == "" || *chatID == 0 {
        fmt.Println("Usage:")
        flag.PrintDefaults()
        return
    }

    // 初始化bot,设置10秒超时
    bot, err := telebot.NewBot(telebot.Settings{
        Token:  *botToken,
        Poller: &telebot.LongPoller{Timeout: 10 * time.Second},
    })
    if err != nil {
        panic(err)
    }

    // 准备发送选项,如果指定了topicID则添加到选项中
    options := &telebot.SendOptions{}
    if *topicID != 0 {
        options.ThreadID = *topicID
    }

    // 发送消息
    sentMessage, err := bot.Send(&telebot.Chat{ID: *chatID}, *messageText, options)
    if err != nil {
        fmt.Println("发送失败:", err)
    } else {
        fmt.Println("消息发送成功:", sentMessage.ID)
    }
}

对于General Topic, ID是1,发送给这个Topic的消息TopicId不需要指定,如果设置成1会提示错误:

发送失败: telegram: Bad Request: message thread not found (400)

5. 进阶用法

发送 Markdown 或 HTML 格式的消息

可以使用 Markdown 或 HTML 格式化文本消息:

options.ParseMode = telebot.ModeMarkdown
sentMessage, err := bot.Send(&telebot.Chat{ID: *chatID}, fmt.Sprintf("*%s*", *messageText), options)

或 HTML 方式:

options.ParseMode = telebot.ModeHTML
sentMessage, err := bot.Send(&telebot.Chat{ID: *chatID}, fmt.Sprintf("<b>%s</b>", *messageText), options)

发送图片到指定话题

photo := &telebot.Photo{File: telebot.FromURL("https://www.baidu.com/img/flexible/logo/pc/result.png")}
sentMessage, err := bot.Send(&telebot.Chat{ID: *chatID}, photo, options)

6. 运行代码

运行的时候输入参数 tokenchattopic 为你的实际值后,topic 为可选参数,比如发给 #General 的消息就可以为空,运行以下命令:

 go run main.go -token=your-bot-token -chat=-1001234567890 -topic=12345

成功后,你应该能在指定的 Telegram 话题中看到机器人发送的消息。


7. 总结

本文介绍了如何使用 Golang 通过 telebot 库将消息发送到 Telegram 超级群组的 指定话题(Topic) 中。

核心步骤包括:

  1. 获取 message_thread_id(话题 ID)。
  2. 使用 telebot 发送消息到指定话题。
  3. 监听消息获取 Topic ID 并进行进阶应用。

通过这些方法,你可以轻松地在 Telegram Bot 中管理不同话题的消息发送。如果你在实践过程中遇到问题,欢迎留言讨论!🚀

8. 常见问题与解决方案

8.1 权限问题

  • 确保 Bot 是群组的管理员
  • Bot 需要有发送消息的权限
  • 如果要发送媒体文件,需要确保有发送媒体的权限

8.2 常见错误码

  • 400 Bad Request: message thread not found: 话题ID不存在或者是General话题(ID=1)
  • 400 Bad Request: chat not found: Chat ID 错误或 Bot 不在群组中
  • 403 Forbidden: bot was blocked by the user: Bot被移出群组或被封禁

8.3 最佳实践

  • 建议实现错误重试机制
  • 对于重要消息,可以添加发送确认和状态检查
  • 考虑实现消息限流,避免触发 Telegram API 限制

示例代码:

// 实现简单的重试机制
func sendWithRetry(bot *telebot.Bot, chat *telebot.Chat, message string, options *telebot.SendOptions) (*telebot.Message, error) {
    maxRetries := 3
    for i := 0; i < maxRetries; i++ {
        sentMessage, err := bot.Send(chat, message, options)
        if err == nil {
            return sentMessage, nil
        }
        time.Sleep(time.Second * time.Duration(i+1))
    }
    return nil, fmt.Errorf("failed after %d retries", maxRetries)
}