You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Telegram机器人批量删帖失败:仅删单用户帖子报错求助

Telegram机器人批量删帖报错:MessageToDeleteNotFound 排查与修复

我开发了两个Telegram机器人功能:

  • 给点击过/start按钮的所有用户群发消息的功能
  • 按ID批量删除用户消息的功能,但执行时仅成功删除一个用户的消息后就抛出错误:aiogram.utils.exceptions.MessageToDeleteNotFound: Message to delete not found

功能代码

1. 群发消息功能代码

@dp.message_handler(commands=['Yes'], state=Post.send_post)
async def process_name(message: Message, state: FSMContext):
    for admin in admins:
        if message.from_user.id == admin:
            async with state.proxy() as data:
                data['send_post'] = message.text
            conn = sqlite3.connect('data.db')
            cur = conn.cursor()
            cur.execute(f'SELECT * FROM users')
            result = cur.fetchall()
            await state.finish()
            print(result)
            try:
                for z in range(len(result)):
                    print(result[z][0])
                    await dp.bot.send_photo(chat_id=result[z][0], photo=data['photo'], caption=data['CAPTHION'], reply_markup=kb)
                    print(z)
                    test = message.message_id + 1
                    await dp.bot.send_message(chat_id=result[z][0], text=f'id поста {test}')
            except BotBlocked:
                print('Пользователь заблокировал бота')
            except ChatNotFound:
                print('Пользователь не запускал бота')

2. 批量删帖功能代码

@dp.message_handler(commands=['deleted'], state=None)
async def send_id(message: Message):
    for admin in admins:
         if message.from_user.id == admin:
                await Post.Sen_id.set()
                await dp.bot.send_message(chat_id=admin, text='Введите ID поста, который нужно удалить.')
    await Post.next()


@dp.message_handler(state=Post.del_mess)
async def deleted_post(message: Message, state: FSMContext):
    for admin in admins:
        if message.from_user.id == admin:
            async with state.proxy() as data:
                data['sen_id'] = message.text
        try:
            conn = sqlite3.connect('data.db')
            cur = conn.cursor()
            cur.execute(f'SELECT * FROM users')
            result = cur.fetchall()
            #message_ids = int(data['sen_id'])
            for z in range(len(result)):
                print('/////////////deleted/////////////')
                print(result)
                print(z)
                await dp.bot.delete_message(chat_id=result[z][0], message_id=data['sen_id'])
                print('Сообщение удалено')
            #chat_id = message.chat.id

            #await dp.bot.delete_message(message.chat.id, message_ids)
            await dp.bot.send_message(chat_id=admin, text='пост удален')
        except BotBlocked:
            print('Пользователь заблокировал бота')
        except ChatNotFound:
            print('Пользователь не запускал бота')

错误原因

  1. 消息ID全局统一的误解
    Telegram中每个用户与机器人的对话是独立的,消息ID是对话内唯一,而非全局统一。你群发时用test = message.message_id + 1(管理员对话的消息ID)作为帖子ID发给用户,但这个ID和用户对话里的消息ID完全不对应,只有碰巧用户对话里有相同数字的消息时才会删除成功,其他情况必然报错。

  2. 消息ID类型错误
    你从状态中获取的data['sen_id']是字符串类型,但delete_message要求message_id是整数,类型不匹配会导致API无法正确识别消息。

  3. 异常捕获不完整且范围错误
    你没有捕获MessageToDeleteNotFound异常,且try-except包裹了整个循环,一旦某个用户触发异常,整个循环直接终止,无法处理后续用户。

修复方案

1. 修改群发逻辑,存储用户对应的真实消息ID

群发时,记录每个用户收到的消息ID到数据库,关联到统一的帖子ID:

@dp.message_handler(commands=['Yes'], state=Post.send_post)
async def process_name(message: Message, state: FSMContext):
    for admin in admins:
        if message.from_user.id == admin:
            async with state.proxy() as data:
                data['send_post'] = message.text
            conn = sqlite3.connect('data.db')
            cur = conn.cursor()
            # 创建帖子消息映射表(如果不存在)
            cur.execute('CREATE TABLE IF NOT EXISTS post_messages(post_id INTEGER, user_id INTEGER, message_id INTEGER)')
            conn.commit()
            cur.execute(f'SELECT * FROM users')
            result = cur.fetchall()
            await state.finish()
            print(result)
            try:
                # 用管理员消息ID+1作为全局帖子标识
                post_id = message.message_id + 1
                for user in result:
                    user_id = user[0]
                    print(user_id)
                    # 发送图片并获取消息对象(包含用户对话中的真实消息ID)
                    photo_msg = await dp.bot.send_photo(chat_id=user_id, photo=data['photo'], caption=data['CAPTHION'], reply_markup=kb)
                    # 发送帖子ID通知并获取消息对象
                    id_msg = await dp.bot.send_message(chat_id=user_id, text=f'id поста {post_id}')
                    # 存储映射关系到数据库
                    cur.execute('INSERT INTO post_messages VALUES (?, ?, ?)', (post_id, user_id, photo_msg.message_id))
                    cur.execute('INSERT INTO post_messages VALUES (?, ?, ?)', (post_id, user_id, id_msg.message_id))
                    conn.commit()
                    print(f"已记录用户{user_id}的消息ID:{photo_msg.message_id}, {id_msg.message_id}")
            except BotBlocked:
                print(f'Пользователь {user_id} заблокировал бота')
            except ChatNotFound:
                print(f'Пользователь {user_id} не запускал бота')
            finally:
                conn.close()

2. 修改删帖逻辑,从数据库获取对应消息ID

@dp.message_handler(commands=['deleted'], state=None)
async def send_id(message: Message):
    for admin in admins:
         if message.from_user.id == admin:
                await Post.Sen_id.set()
                await dp.bot.send_message(chat_id=admin, text='Введите ID поста, который нужно удалить.')
    await Post.next()

@dp.message_handler(state=Post.del_mess)
async def deleted_post(message: Message, state: FSMContext):
    for admin in admins:
        if message.from_user.id == admin:
            try:
                # 转换输入为整数类型
                post_id = int(message.text)
                async with state.proxy() as data:
                    data['sen_id'] = post_id
                conn = sqlite3.connect('data.db')
                cur = conn.cursor()
                # 根据帖子ID查询所有需要删除的消息
                cur.execute('SELECT user_id, message_id FROM post_messages WHERE post_id = ?', (post_id,))
                messages_to_delete = cur.fetchall()
                # 逐个处理用户的消息删除
                for user_id, msg_id in messages_to_delete:
                    try:
                        await dp.bot.delete_message(chat_id=user_id, message_id=msg_id)
                        print(f"Удалено сообщение {msg_id} для пользователя {user_id}")
                    except BotBlocked:
                        print(f'Пользователь {user_id} заблокировал бота')
                    except ChatNotFound:
                        print(f'Пользователь {user_id} не запускал бота')
                    except MessageToDeleteNotFound:
                        print(f'Сообщение {msg_id} для пользователя {user_id} не найдено')
                await dp.bot.send_message(chat_id=admin, text='пост удален')
                await state.finish()
            except ValueError:
                await dp.bot.send_message(chat_id=admin, text='Некорректный ID поста,请输入数字')
            finally:
                if 'conn' in locals():
                    conn.close()

3. 额外优化点

  • 数据库连接放到finally块确保关闭,避免连接泄漏
  • 对单个用户的删除操作单独捕获异常,不影响其他用户
  • 验证输入的帖子ID是否为有效整数,提前拦截错误输入

内容的提问来源于stack exchange,提问作者user380703

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 17:45:32