Rich messages¶
Bot API 10.1 added rich messages: block-level structure (headings, paragraphs,
code blocks, tables, collapsibles, math) that plain messages cannot express.
send_rich_message is one more Bot method; build its content with
RichMessage plus the inline helpers in moonlygram.rich.
from moonlygram import RichMessage
from moonlygram.rich import bold, link
msg = (
RichMessage()
.heading("Release notes")
.paragraph("Shipped ", bold("rich messages"), ", see ", link("the docs", "https://example.com"))
.code_block("pip install -U moonlygram", language="bash")
)
await bot.send_rich_message(chat_id, html=msg)
Everything is HTML-escaped as it is added, so plain strings are always safe to
pass; use raw() for an HTML fragment you have built yourself.
From Markdown¶
markdown_to_rich converts an existing Markdown string to rich-message HTML:
from moonlygram import markdown_to_rich
await bot.send_rich_message(chat_id, html=markdown_to_rich("# Hi\n\nSome **bold** text."))
Structured blocks¶
Bot API 10.2 adds a third content form. Instead of an HTML or Markdown string,
describe the message as a list of block objects and pass them as blocks. The
block types live in moonlygram.rich.
from moonlygram.rich import (
InputRichBlockList,
InputRichBlockListItem,
InputRichBlockParagraph,
InputRichBlockSectionHeading,
)
await bot.send_rich_message(
chat_id,
blocks=[
InputRichBlockSectionHeading("Release notes", size=1),
InputRichBlockParagraph("Two things shipped:"),
InputRichBlockList(
items=[
InputRichBlockListItem(blocks=[InputRichBlockParagraph("Structured blocks")]),
InputRichBlockListItem(blocks=[InputRichBlockParagraph("Ephemeral messages")]),
]
),
],
)
Pass exactly one of html, markdown, or blocks. When html or markdown
text references a file through a tg://photo?id=, tg://video?id=, or
tg://audio?id= link, supply those files with media, a list of
InputRichMessageMedia.
Streaming¶
send_rich_message_draft updates an ephemeral draft repeatedly (about a 30s
TTL); send the final version with send_rich_message. In a blocks draft,
InputRichBlockThinking renders a "thinking" placeholder for content that has
not arrived yet; it is valid only in drafts.
Editing¶
edit_rich_message_text replaces the text of an already-sent message with
rich content. It takes the same html / markdown / blocks / media forms
as send_rich_message:
await bot.edit_rich_message_text(
chat_id=chat_id, message_id=message_id, markdown="All **done**."
)
See the rich API reference for every block and inline helper.