- 后端
- 即时通讯
- API设计
【免费下载链接】aiogram
aiogram is a modern and fully asynchronous framework for Telegram Bot API written in Python using asyncio
RichTextEmailAddress 是 aiogram 中用于表示"带有邮箱地址的富文本"的核心类型节点,它隶属于 Telegram Bot API 的 Rich Text(富文本消息)体系,服务于sendRichMessage等新一代富消息发送接口。本文以 RichTextEmailAddress API 文档 为主线,结合 类型源码、判别联合实现 与 回归测试,讲解该节点的字段语义、在RichTextUnion中的反序列化机制,以及如何在实际 bot 中构造并发送包含邮箱地址的富文本消息。
一、文档与源码定位:一个 autodoc 驱动的类型页
docs/api/types/rich_text_email_address.rst是 aiogram 文档站中该类型的唯一入口,其内容非常精简,仅包含标题与一段 Sphinxautomodule指令:
#################### RichTextEmailAddress #################### .. automodule:: aiogram.types.rich_text_email_address :members: :member-order: bysource :undoc-members: True :exclude-members: model_config,model_fields这说明该文档页是完全由源码 docstring 与类型注解自动生成的:automodule从 aiogram/types/rich_text_email_address.py 拉取类定义、字段与构造函数签名,member-order: bysource按源码顺序排列成员,undoc-members: True保证未写 docstring 的成员也会被收录,而model_config、model_fields两个 Pydantic 内部属性被排除在文档之外。因此,要完整理解该类型,必须直接阅读其源码实现——这正是本文展开的核心依据。
二、类定义与字段语义
RichTextEmailAddress定义在 aiogram/types/rich_text_email_address.py,继承自RichText(即 aiogram/types/rich_text.py 中的RichText基类),本质是一个基于 PydanticBaseModel的 Telegram API 对象模型。其官方语义为:"A text with an email address."(一段带邮箱地址的文本)。
类中共有三个字段:
| 字段 | 类型 | 必填 | 语义 |
|---|---|---|---|
type | Literal[RichTextType.EMAIL_ADDRESS] | 否(有默认值) | 富文本类型,固定为'email_address',由 RichTextType 枚举 中的EMAIL_ADDRESS = "email_address"提供 |
text | RichTextUnion | 是 | 该节点承载的文本内容 |
email_address | str | 是 | 关联的邮箱地址字符串 |
其中type被声明为Literal[RichTextType.EMAIL_ADDRESS] = RichTextType.EMAIL_ADDRESS,即它是一个常量标签字段,构造时无需(也不应)手动指定。text的类型是RichTextUnion,这是一个非常关键的联合类型,下文单独展开。
源码在TYPE_CHECKING块中还提供了由butcher工具自动生成的__init__签名,它不参与运行时逻辑,仅用于让 IDE 与静态类型检查器在没有 Pydantic 插件的情况下也能获得完整的构造提示:
def __init__( __pydantic__self__, *, type: Literal[RichTextType.EMAIL_ADDRESS] = RichTextType.EMAIL_ADDRESS, text: RichTextUnion, email_address: str, **__pydantic_kwargs: Any, ) -> None: super().__init__(type=type, text=text, email_address=email_address, **__pydantic_kwargs)2.1 基类链路:TelegramObject → RichText
类型继承链为RichTextEmailAddress→RichText→TelegramObject。RichText本身只承载一段说明性 docstring,列举了当前全部 25 种富文本子类型(Bold、Italic、Underline、Strikethrough、Spoiler、DateTime、TextMention、Subscript、Superscript、Marked、Code、CustomEmoji、MathematicalExpression、Url、EmailAddress、PhoneNumber、BankCardNumber、Mention、Hashtag、Cashtag、BotCommand、Button、Anchor、AnchorLink、Reference、ReferenceLink),见 aiogram/types/rich_text.py。
真正提供数据能力的是TelegramObject(aiogram/types/base.py),它配置了 Pydantic 的关键行为:
use_enum_values=True:枚举字段(包括type)在序列化时直接使用枚举的字符串值,因此发送给 Telegram 时type就是"email_address";frozen=True:模型不可变,实例构造后字段只读;extra="allow":允许额外字段,对 Telegram 侧新增字段保持向前兼容;validate_assignment=True:赋值时同样触发校验;defer_build=True:延迟构建模型,配合递归联合类型(如RichTextUnion)使用。
三、text字段与 RichTextUnion 判别联合
RichTextUnion定义在 aiogram/types/rich_text_union.py,它是 aiogram 富文本体系中最重要的类型之一,其类型别名可归纳为三类合法取值:
- 纯字符串:如
"hello@example.com",表示普通文本; - 字符串/节点的数组:如
["a", RichTextBold(text="b")],表示一组依次渲染的子片段; - 任意一种
RichText*模型:包括RichTextBold、RichTextItalic、RichTextSpoiler、RichTextUrl、RichTextEmailAddress等 25 个具体子类。
由于联合成员既包含str、list这样的 Python 原生类型,又包含以type字段区分的 Pydantic 模型,它不能像普通 Telegram 联合类型那样直接使用Field(discriminator="type")。aiogram 的解决方案是自定义一个运行时判别函数_rich_text_union_tag:
def _rich_text_union_tag(value: Any) -> Any: if isinstance(value, str): return "str" if isinstance(value, (list, tuple)): return "list" if isinstance(value, dict): return value.get("type") return getattr(value, "type", None)即:字符串按其 Python 类型打"str"标签,数组打"list"标签,字典与模型实例则读取其type字段(如"email_address")作为标签。最终通过TypeAliasType与Annotated/Tag/Discriminator组合成一个以type为判别键的判别联合。
3.1 为什么需要判别联合:回归测试 #1925
CHANGES/1925.bugfix.rst 记录了一次重要修复:此前RichTextUnion是一个普通的智能联合,Pydantic 会在每一层嵌套上逐个尝试所有成员,导致"加粗套斜体套剧透"这类多层嵌套富文本的校验呈指数级变慢,甚至冻结事件循环。修复后改为按type判别的联合,回归测试 中用一个 5 层嵌套的更新负载验证了每个节点都能正确解析为具体类型,并用 POSIX 的SIGALRM计时器断言:30 层嵌套的RichTextUnion校验耗时小于 1 秒(超过 5 秒即判定回归)。
这对使用者的实际意义是:RichTextEmailAddress作为RichTextUnion的成员之一,可以放心地与RichTextBold、RichTextItalic等节点无限嵌套组合,而不会遭遇解析性能陷阱。
四、从节点到消息:构造带邮箱地址的富文本
RichTextEmailAddress不会独立出现,它总是被嵌套在富消息(Rich Message)结构中。发送富消息使用SendRichMessage方法(aiogram/methods/send_rich_message.py),其 API 方法名为sendRichMessage,核心参数为chat_id与rich_message(类型为InputRichMessage)。
InputRichMessage(aiogram/types/input_rich_message.py)提供三种互斥的内容描述方式:html、markdown或blocks。其中blocks是结构化方式——一个InputRichBlockUnion列表,每个块可以是段落(InputRichBlockParagraph)、标题、引用、表格等(完整清单见 aiogram/types/input_rich_block.py)。而段落块的text字段正是RichTextUnion,邮箱地址节点就挂在这里。
以下示例构造一条"正文 + 可点击邮箱地址"的富消息并通过send_rich_message发送:
from aiogram import Bot from aiogram.types import ( InputRichBlockParagraph, InputRichMessage, RichText, RichTextEmailAddress, ) bot = Bot("TOKEN") await bot.send_rich_message( chat_id=chat_id, rich_message=InputRichMessage( blocks=[ InputRichBlockParagraph( text=RichText( [ "欢迎来信:", RichTextEmailAddress( text="contact@example.com", email_address="contact@example.com", ), ] ) ) ] ), )关键点说明:
RichText与RichTextEmailAddress同为RichTextUnion的合法成员,可直接混用;text字段是"用户看到的渲染文本",email_address是"被识别并关联的邮箱地址",两者既可以相同(如上例),也可以不同,例如显示"联系我们"而关联真实邮箱;type字段无需传参,默认即为"email_address";- 若消息同时包含媒体块,bot 需具备对应媒体的发送权限(见
SendRichMessagedocstring)。
InputRichMessage还支持is_rtl(从右到左渲染)与skip_entity_detection(跳过 URL、邮箱、@用户名、话题标签等实体的自动识别),后者对显式构造的富文本节点没有影响。
五、与相近类型的对比:Url、PhoneNumber、BankCardNumber
RichTextEmailAddress在结构上与其"姐妹节点"高度相似,它们共享完全相同的字段布局:一个固定的type常量 + 一个text: RichTextUnion+ 一个专用承载字段。以 RichTextUrl 与 RichTextPhoneNumber 为例:
| 类型 | type 常量 | 承载字段 | 字段语义 |
|---|---|---|---|
RichTextUrl | 'url' | url: str | 链接地址 |
RichTextEmailAddress | 'email_address' | email_address: str | 邮箱地址 |
RichTextPhoneNumber | 'phone_number' | phone_number: str | 电话号码 |
同样模式的还有RichTextBankCardNumber(银行卡号)、RichTextHashtag、RichTextCashtag、RichTextBotCommand、RichTextMention等。理解这一点后,掌握其中一个节点即可触类旁通地使用整个"实体型富文本"家族。
六、使用建议与注意事项
- 序列化形态:由于
use_enum_values=True,RichTextEmailAddress序列化后为{"type": "email_address", "text": ..., "email_address": ...},与 Telegram Bot API 的RichTextEmailAddress定义(https://core.telegram.org/bots/api#richtextemailaddress)保持一致; - 嵌套自由:
text可以继续嵌套其他富文本节点,例如让邮箱地址局部加粗:RichTextEmailAddress(text=[RichTextBold(text="me@example.com")], email_address="me@example.com"),性能已由判别联合机制保证; - 只读模型:
TelegramObject默认frozen=True,构造后不能修改字段,需要变更时请重新构造实例; - 文档查阅方式:本类型的正式 API 文档由 docs/api/types/rich_text_email_address.rst 提供,它是整个 docs/api/types 目录下 638 个 API 页面之一,体系中的其他富文本节点文档位于同目录,例如 rich_text.rst、rich_text_url.rst、input_rich_message.rst,发送方法见 send_rich_message.rst。
七、小结
RichTextEmailAddress是 aiogram 富文本消息体系中的一个"小而专"的实体节点:三个字段、一个固定类型常量、一套统一基类。它的真正复杂性体现在两点——其text字段所指向的RichTextUnion判别联合(及其防指数级退化的回归测试),以及它作为InputRichMessage.blocks结构化内容的一环如何参与sendRichMessage的实际发送。理解这两个层面,即可在 aiogram 中熟练构造带邮箱地址、链接、电话等实体的下一代富文本消息。
- 后端
- 即时通讯
- API设计
【免费下载链接】aiogram
aiogram is a modern and fully asynchronous framework for Telegram Bot API written in Python using asyncio
相关推荐
aiogram 富文本类型详解:RichTextCashtag 的字段、联合类型判别与实战用法
aiogram 富文本类型详解:RichTextCashtag 的字段、联合类型判别与实战用法 导读 本文围绕 aiogram 对 Telegram Bot A
后端即时通讯API设计aiogram 中 RichTextStrikethrough 详解:富文本消息里删除线节点的构造、联合类型分发与发送实战
aiogram 中 RichTextStrikethrough 详解:富文本消息里删除线节点的构造、联合类型分发与发送实战 本文以 aiogram 官方 API
后端即时通讯API设计aiogram 中 RichTextReference 深度解析:Telegram 富文本引用节点的字段模型、联合类型判别与实战用法
aiogram 中 RichTextReference 深度解析:Telegram 富文本引用节点的字段模型、联合类型判别与实战用法 本文围绕 RichText
后端即时通讯API设计
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考