telegram-userbots
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTelegram userbots — MTProto, and what it costs
Telegram userbots——MTProto,以及它付出的代价
A bot token is issued to software. An MTProto session is a logged-in human
being — the same authority the person has, held in a file, with none of the
protections a token has. Everything in this skill follows from that one
difference.
Read against Telethon 1.44.0 and on 2026-08-25. Telethon
minor releases change session and entity-cache behaviour; the version you are on
is a fact to check, not to assume.
core.telegram.orgDeep material, loaded on demand:
| Read | When |
|---|---|
| logging in, storing a session, rotating one, or moving between machines |
| anything that loops over chats, users or messages — FloodWait, pacing, takeout |
| resolving peers, iterating history, downloading media at scale |
bot token 是签发给软件的。一个 MTProto session 就是一个已登录的真人——它拥有与该用户本人相同的权限,而且这些权限被保存在一个文件里,不具备 token 所具有的任何保护。本 skill 中的一切都源于这一差异。
依据 Telethon 1.44.0 与 ,核对日期为 2026-08-25。Telethon 的次要版本发布会改变 session 和 entity-cache 行为;你当前使用的版本是需要核实的事实,而不是可以想当然的假设。
core.telegram.org深度资料,按需加载:
| 阅读 | 何时 |
|---|---|
| 登录、存储 session、轮换 session,或在不同机器之间迁移 |
| 任何遍历 chats、users 或 messages 的操作——FloodWait、节奏控制、takeout |
| 解析 peers、遍历历史记录、大规模下载媒体 |
First: do you actually need one?
首先:你真的需要 userbot 吗?
Answer this before writing a line, and write the answer down.
| The job | Bot API can | Verdict |
|---|---|---|
| React to messages in chats the bot is in | yes | use a bot |
| Send to users who started the bot | yes | use a bot |
| Read a public channel it is admin of | yes | use a bot |
| Read history of a channel it does not administer | no | userbot |
| Read a chat's past, from before it joined | no | userbot |
| Act as a specific person | no | userbot |
| Download a file over 20 MB | no | userbot, or a local Bot API server |
| Enumerate a group's members at scale | no | userbot, and see the risk below |
The local Bot API server closes the file ceiling without an account. Reaching
for a user session because of a 21 MB video is trading a permanent liability for
an infrastructure task you were going to have anyway.
The refusal, and it is not a formality: a user account can be limited or
banned, and Telegram does not explain, appeal quickly, or restore what was in it.
If the account is a real person's, the blast radius is their messages, their
groups and their logins. Automating a personal account is a decision with a
named owner or it is not a decision.
在写第一行代码前先回答这个问题,并把答案写下来。
| 任务 | Bot API 能做到吗 | 结论 |
|---|---|---|
| 对 bot 所在 chats 中的消息作出反应 | 是 | 使用 bot |
| 向启动 bot 的用户发送消息 | 是 | 使用 bot |
| 读取 bot 担任管理员的公开 channel | 是 | 使用 bot |
| 读取 bot 未管理的 channel 历史 | 否 | userbot |
| 读取 chat 加入之前的历史 | 否 | userbot |
| 以特定人员身份操作 | 否 | userbot |
| 下载超过 20 MB 的文件 | 否 | userbot,或使用本地 Bot API server |
| 大规模枚举群组成员 | 否 | userbot,并参阅下方风险 |
本地 Bot API server 无需账户即可突破文件大小上限。 仅仅因为要处理一个 21 MB 的视频就改用 user session,就是拿一项永久性责任去换一项你本来也总要搭建的基础设施工作。
要拒绝这种做法,而且这不是走形式: 用户账户可能受到限制或封禁,而 Telegram 不会解释原因、不支持快速申诉,也不会恢复其中原有的数据。如果该账户属于真人,影响范围会涵盖此人的消息、群组和登录状态。自动化个人账户必须有一位明确的责任人,否则就不该做这个决定。
The session file is the credential
session 文件就是凭据
python
import os
from telethon import TelegramClient
from telethon.sessions import StringSession
client = TelegramClient(
session=StringSession(os.environ["TG_SESSION"]), # from the secret store
api_id=int(os.environ["TG_API_ID"]),
api_hash=os.environ["TG_API_HASH"],
)- A file grants full access to the account, without the password and without the 2FA prompt. Copying one to another machine logs that machine in. It belongs in
.session, in a secret store, in backups you would give a password the same treatment — and never in an image layer or a log..gitignore - /
api_idcome fromapi_hashand identify the application, not the account. They are not a session and not a secret of the same weight, but they are still not public.my.telegram.org - Losing a session is recoverable; leaking one is an incident. Revoke from the account's own Devices screen, which ends that session everywhere.
- Log Out is not a lockout, and termination comes from an older session.
can return a
auth.logOutthat skips the next login code, so the two-step password is the real gate; a session under 24 hours old cannot terminate others (future_auth_token). Accepting aFRESH_RESET_AUTHORISATION_FORBIDDENlink logs in whoever generated it. List, watch (tg://login?token=) and terminate sessions:UpdateNewAuthorization.references/sessions-and-auth.md - Verified on this machine on 2026-08-25: five of five Telethon projects gitignore the session and none has one tracked in git — the one trap this estate has actually closed. Keep it closed.
python
import os
from telethon import TelegramClient
from telethon.sessions import StringSession
client = TelegramClient(
session=StringSession(os.environ["TG_SESSION"]), # from the secret store
api_id=int(os.environ["TG_API_ID"]),
api_hash=os.environ["TG_API_HASH"],
)- 一个 文件可在不需要密码、也不需要 2FA 提示的情况下授予账户的完整访问权限。 将它复制到另一台机器,就等于让那台机器登录。它应放在
.session中、存于 secret store、备份时也要像密码一样受到同等保护——绝不能进入 image layer 或日志。.gitignore - /
api_id来自api_hash,标识的是 application,而非账户。 它们不是 session,敏感程度也不相同,但仍不应公开。my.telegram.org - 丢失 session 可以恢复;泄露 session 就是安全事件。 在账户自身的 Devices 页面中撤销它,会在所有设备上终止该 session。
- Log Out 不是锁定,而终止其他 session 必须来自一个更老的 session。 可以返回一个
auth.logOut,从而跳过下一次登录验证码,因此两步验证密码才是真正的关卡;创建时间不足 24 小时的 session 无法终止其他 session(future_auth_token)。接受FRESH_RESET_AUTHORISATION_FORBIDDEN链接会登录生成该链接的一方。列出、监听(tg://login?token=)并终止 session:UpdateNewAuthorization。references/sessions-and-auth.md - 本机于 2026-08-25 验证:五个 Telethon 项目全部将 session 加入了 gitignore,且没有任何一个在 git 中追踪 session 文件——这是这组代码库实际已经堵住的一个陷阱。保持它被堵住。
FloodWaitError
is the API working
FloodWaitErrorFloodWaitError
是 API 正常运作的信号
FloodWaitErrorpython
from telethon.errors import FloodWaitError
try:
await client.send_message(peer, text)
except FloodWaitError as e:
if e.seconds > MAX_ACCEPTABLE: # a decision, not a sleep
raise
await asyncio.sleep(e.seconds + 1)
await client.send_message(peer, text)- It is not a failure to swallow and not a signal to retry blindly. It names exactly how long to wait; anything else is guessing at a number Telegram already told you.
- A very large is a different event. Minutes mean you are pacing too hard; hours mean the account is being limited, and continuing is how a limit becomes a ban. Cap it, alert, stop.
seconds - Sleeping inside a request handler is how one flood becomes an outage. The wait belongs in a worker with a queue, not in the path a user is waiting on.
- Measured across six Telethon projects here on 2026-08-25: three of six handle
at all. The other three run until the first limit and then stop, in whatever state they were in.
FloodWaitError
python
from telethon.errors import FloodWaitError
try:
await client.send_message(peer, text)
except FloodWaitError as e:
if e.seconds > MAX_ACCEPTABLE: # a decision, not a sleep
raise
await asyncio.sleep(e.seconds + 1)
await client.send_message(peer, text)- 它不是可以吞掉的失败,也不是可以盲目重试的信号。 它会准确告诉你需要等待多久;换成其他做法,就是在猜测 Telegram 已经明确给出的数字。
- 非常大意味着发生了另一类事件。 以分钟计,说明节奏过快;以小时计,说明账户正受到限制,而继续运行正是限制升级为封禁的方式。应设置等待上限、发出告警并停止。
seconds - 在请求处理器内部 sleep,是一次 flood 演变成服务中断的方式。 等待应放在带队列的 worker 中,而不能位于用户正在等待的请求路径上。
- 于 2026-08-25 对这里的六个 Telethon 项目进行测量:六个项目中有三个处理了 。 另外三个会一直运行到首次触发限制,然后停下,并停留在各自当时的状态中。
FloodWaitError
Pin the minor, and know why
锁定次要版本,并知道原因
Four bots in this estate pin while a fifth runs , and
the pin carries its reason in : minor releases change session
and entity-cache behaviour, and a jump of seven minors on a live bot needs its own
change with its own verification.
telethon==1.37.01.44.0requirements.txtThat is the right shape and it is worth stating as doctrine. A userbot's
dependency is not a library, it is a protocol client holding a login. An
upgrade can invalidate a session format, change what costs, or move
an exception's module. Upgrade deliberately, one bot at a time, with a session
you can recreate.
get_entity这组代码库中有四个 bot 固定使用 ,第五个使用 ,并且该固定版本在 中附有理由:次要版本发布会改变 session 和 entity-cache 行为,而线上 bot 一次跨越七个次要版本,需要作为一项独立变更并配套自己的验证。
telethon==1.37.01.44.0requirements.txt这是正确的做法,也值得明确为原则。userbot 的依赖项不是一个库,而是一个持有登录态的协议客户端。 升级可能使 session 格式失效、改变 的成本,或移动异常所在的模块。升级应有计划地逐个 bot 进行,并使用一个能够重新创建的 session。
get_entityEntities are resolved, and resolution is not free
Entities 需要解析,而解析并非零成本
get_entity- Prefer ids you already have. A cached costs nothing; a username costs a request.
InputPeer - usually means the account has never seen that peer, not that the id is wrong. A user account can only address what it has encountered.
PeerIdInvalidError - Iterate with the library's own iterators (,
iter_messages) and let them page; hand-rolled offsets re-request and re-trip the limits.iter_dialogs - For a bulk export, exists and is the sanctioned path — it raises the limits for exactly this and tells Telegram what you are doing.
takeout
Detail in .
references/entities-and-history.mdget_entity- 优先使用你已有的 ids。 已缓存的 不产生成本;username 则需要一次请求。
InputPeer - 通常意味着账户从未见过该 peer,而不是 id 错误。 用户账户只能寻址它已经遇到过的对象。
PeerIdInvalidError - 使用库自带的迭代器(、
iter_messages)并让它们自行分页。 手写的 offset 会重复发起请求并再次触发限制。iter_dialogs - 对于批量导出,已经存在,而且是官方认可的路径——它会针对此用途提高限制,并让 Telegram 知道你正在执行此操作。
takeout
详见 。
references/entities-and-history.mdTwo accounts, two lifetimes
两个账户,两种生命周期
A userbot has a second failure mode a bot does not: the human logs in
somewhere, changes the password, or terminates sessions, and your process dies
holding a session that is no longer valid. This is a terminal / revoked
auth state, not a transient one: the process may still be LIVE, but it is NOT
READY, and a restart just re-loops a login that can never succeed. Surface it
as an alert with the account named, stop work until FRESH auth (a re-login that
needs the phone), and never a crash loop — the same three-state contract
's error-tracking states for any long-lived authenticated
connection: liveness, readiness, degraded_auth (transient retries, terminal
stops). A supervisor restart is for the policy only; a
revoked session is and lands on the STOP-and-alert row of that
skill's recovery-contract table, so the identical event cannot draw opposite
actions in the two packs. Never put a userbot on the critical path of
something a bot could
serve.
sheleg-devrecoverableterminaluserbot 有一个 bot 没有的第二种故障模式:真人会在某处登录、更改密码或终止 session,而你的进程会带着一个已失效的 session 死亡。这是一种 terminal / revoked 认证状态,而非瞬时状态:进程可能仍为 LIVE,但不是 READY,而重启只会让一次永远不可能成功的登录重新循环。应以包含账户名称的告警将其暴露出来,停止工作,直到获得 FRESH auth(需要手机号码的重新登录),绝不能形成崩溃循环——这与 的错误跟踪为任何长生命周期认证连接定义的三状态契约完全一致:liveness、readiness、degraded_auth(瞬时重试,终止性停止)。supervisor 重启只适用于 策略;被撤销的 session 属于 ,应落到该 skill 恢复契约表的 STOP-and-alert 行,因此两个技能包中的同一事件不能触发相反的处理方式。 绝不要把 userbot 放在 bot 本可胜任任务的关键路径上。
sheleg-devrecoverableterminalBefore you ship
上线前
- The reason a user account is required is written down, and the bot-API alternative was checked (§ First: do you actually need one?).
- The session is in a secret store, gitignored, and revocable (§ The session file is the credential).
- is caught, capped and alerted on — never slept off unbounded (§
FloodWaitErroris the API working).FloodWaitError - The client version is pinned, and the upgrade is its own change (§ Pin the minor).
- A dead session pages a human rather than restarting forever (§ Two accounts, two lifetimes).
- The account has a two-step password, and someone watches its sessions:
a new reaches a human, and the oldest trusted session is the one that terminates (§ The session file is the credential).
UpdateNewAuthorization
- 已写明必须使用用户账户的原因,并已检查 Bot API 替代方案(§ 首先:你真的需要 userbot 吗?)。
- session 位于 secret store 中、已加入 gitignore,并且可撤销(§ session 文件就是凭据)。
- 已捕获 ,设置上限并告警——绝不无限制地 sleep 等待(§
FloodWaitError是 API 正常运作的信号)。FloodWaitError - 客户端版本已固定,且升级是一项独立变更(§ 锁定次要版本)。
- session 失效时会呼叫人工处理,而不是无限重启(§ 两个账户,两种生命周期)。
- 账户已设置两步验证密码,并且有人监看其 session:新的 会通知人工,由最老的受信任 session 执行终止操作(§ session 文件就是凭据)。
UpdateNewAuthorization
Triggers
触发词
More phrases that route here: "user account", "read channel history", "api_hash", "телетон".
更多会路由到这里的短语:"user account"、"read channel history"、"api_hash"、"телетон"。