Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Message Formatting

Telegram supports rich text formatting through message entities: positional markers that indicate bold, italic, code, links, and more.

Quickest way: InputMessage constructors

The simplest approach is InputMessage::markdown or InputMessage::html, which parse the text and attach entities in one call:

#![allow(unused)]
fn main() {
use ferogram::InputMessage;

// Markdown
let msg = InputMessage::markdown("**Bold**, _italic_, `code`");

// HTML
let msg = InputMessage::html("<b>Bold</b>, <i>italic</i>, <code>code</code>");

client.send_message(peer, msg).await?;
}

If you just want to send without building an InputMessage first, the convenience methods do the same thing in one step:

#![allow(unused)]
fn main() {
client.send_message(peer, InputMessage::html("<b>Bold</b> and <i>italic</i>")).await?;
client.send_message(peer, InputMessage::markdown("**Bold** and _italic_")).await?;
}

Using parse_markdown directly

If you need the (String, Vec<MessageEntity>) tuple for further processing:

#![allow(unused)]
fn main() {
use ferogram::parsers::parse_markdown;
use ferogram::InputMessage;

let (plain, entities) = parse_markdown("**Bold text**, _italic_, `inline code`");

let msg = InputMessage::text(plain).entities(entities);
client.send_message(peer, msg).await?;
}

Markdown syntax

SyntaxEntity
**text** or *text*Bold
_text_Italic
__text__Underline
~text~Strikethrough
||text||Spoiler
`text`Code (inline)
```lang\ncode\n```Pre (code block)
[label](url)TextUrl
[label](tg://user?id=123)MentionName
![text](tg://emoji?id=123)CustomEmoji
> line at line startBlockquote
**> line at line startExpandable blockquote
\*, \_, \~Escaped literal character

parse_markdown follows the Telegram Bot API MarkdownV2 spec. __text__ is Underline, not Italic. For the legacy V1 behaviour call parse_markdown_v1 (deprecated, removed in 0.4.0).

HTML syntax

Supported tags:

TagEntity
<b>, <strong>Bold
<i>, <em>Italic
<u>, <ins>Underline
<s>, <del>, <strike>Strikethrough
<tg-spoiler>, <span class="tg-spoiler">Spoiler
<code>Code (inline)
<pre>Pre (code block)
<pre><code class="language-X">Pre with language
<blockquote>Blockquote
<blockquote expandable>Expandable (collapsible) blockquote
<tg-time unix="N" format="F">FormattedDate
<a href="url">TextUrl
<a href="tg://user?id=123">MentionName
<tg-emoji emoji-id="123">CustomEmoji
<br>Newline

Building entities manually

For full control, construct MessageEntity values directly:

#![allow(unused)]
fn main() {
use ferogram_tl_types as tl;

let text = "Hello world";
let entities = vec![
    tl::enums::MessageEntity::Bold(tl::types::MessageEntityBold {
        offset: 0,
        length: 5,
    }),
    tl::enums::MessageEntity::Code(tl::types::MessageEntityCode {
        offset: 6,
        length: 5,
    }),
];

let msg = InputMessage::text(text).entities(entities);
}

Pre block with language

#![allow(unused)]
fn main() {
tl::enums::MessageEntity::Pre(tl::types::MessageEntityPre {
    offset:   0,
    length:   code_text.encode_utf16().count() as i32,
    language: "rust".into(),
})
}

Mention by user ID

#![allow(unused)]
fn main() {
tl::enums::MessageEntity::MentionName(tl::types::MessageEntityMentionName {
    offset:  0,
    length:  label.encode_utf16().count() as i32,
    user_id: 123456789,
})
}

Blockquote

messageEntityBlockquote has an optional collapsed flag:

#![allow(unused)]
fn main() {
tl::enums::MessageEntity::Blockquote(tl::types::MessageEntityBlockquote {
    collapsed: false, // true = collapsible quote
    offset: 0,
    length: text.encode_utf16().count() as i32,
})
}

FormattedDate

Displays a Unix timestamp in the user’s local timezone and locale. Set the boolean flags you want; the rest default to false:

#![allow(unused)]
fn main() {
tl::enums::MessageEntity::FormattedDate(tl::types::MessageEntityFormattedDate {
    relative:    false,
    short_time:  false,
    long_time:   false,
    short_date:  true,  // e.g. "Jan 5"
    long_date:   false,
    day_of_week: false,
    offset: 0,
    length: placeholder_text.encode_utf16().count() as i32,
    date:   1736000000, // Unix timestamp
})
}

Generating markup from entities

Both generate_markdown and generate_html are available if you need to serialise entities back to text:

#![allow(unused)]
fn main() {
use ferogram::parsers::{generate_markdown, generate_html};

let md  = generate_markdown(plain_text, &entities);
let htm = generate_html(plain_text, &entities);
}

generate_markdown emits full MarkdownV2 syntax including __text__ for Underline, ~text~ for Strike, and > prefix for Blockquote.

All entity types

VariantDescription
BoldBold text
ItalicItalic text
UnderlineUnderlined (HTML only)
StrikeStrikethrough
SpoilerHidden until tapped
CodeMonospace inline
PreCode block (optional language)
TextUrlHyperlink with custom label
UrlAuto-detected URL
EmailAuto-detected email
PhoneAuto-detected phone number
Mention@username mention
MentionNameInline mention by user ID
Hashtag#hashtag
Cashtag$TICKER
BotCommand/command
BankCardBank card number
BlockquoteBlock quote, optionally collapsible
CustomEmojiCustom emoji by document ID
FormattedDateUnix timestamp rendered in local time