Messages
Messages are at the heart of a messaging platform.
In Telethon, you will be using the Message
class to interact with them.
Fetching messages
The most common way to actively fetch messages using the Client.get_messages()
method:
# Get the last message in a chat (by setting the limit to 1).
last_message = (await client.get_messages(chat, 1))[0]
# Iterate over all messages in a chat, starting from the oldest message (by using reversed).
async for message in reversed(client.get_messages(chat)):
print(message.sender.name, message.text_html)
You can also perform a fuzzy text search with the Client.search_messages()
method.
The search will be performed server-side by Telegram, so the rules for how it works are also fuzzy.
If you want to search for messages in all the chats you’re part of, you can use Client.search_all_messages()
.
Lastly, Client.send_message()
also returns the Message
that you just sent.
The most common way to passively listen to incoming messages is using the NewMessage
event:
from telethon import events
@client.on(events.NewMessage)
async def first(event):
print(event.chat.name, ':', event.text)
See also
The Updates concept for an in-depth explanation on using events.
Formatting messages
The library supports 3 formatting modes: no formatting, CommonMark, HTML.
Telegram does not natively support markdown or HTML. Clients such as Telethon parse the text into a list of formatting MessageEntity at different offsets.
Note that CommonMark’s markdown is not fully compatible with HTTP Bot API’s MarkdownV2 style, and does not support spoilers:
*italic* and _italic_
**bold** and __bold__
# headings are underlined
~~strikethrough~~
[inline URL](https://www.example.com/)
[inline mention](tg://user?id=ab1234cd6789)
custom emoji image with ![👍](tg://emoji?id=1234567890)
`inline code`
```python
multiline pre-formatted
block with optional language
```
HTML is also not fully compatible with HTTP Bot API’s HTML style, and instead favours more standard HTML elements:
strong
andb
for bold.em
andi
for italics.u
for underlined text.del
ands
for strikethrough.blockquote
for quotes.details
for hidden text (spoiler).code
forinline code
pre
for multiple lines of code.a
for links.img
for inline images (only custom emoji).
Both markdown and HTML recognise the following special URLs using the tg:
protocol:
tg://user?ref=u.123.A4B5
for inline mentions. You can obtain the reference usingtypes.Peer.ref
(as inf'tg://user?ref={user.ref}'
). You can also the?id=
query parameter withtypes.User.id
instead, but the mention may fail.tg://emoji?id=1234567890
for custom emoji. You must use the document identifier as the value. The alt-text of the image must be a emoji such as 👍.
To obtain a message’s text formatted, use types.Message.text_markdown
or types.Message.text_html
.
To send a message with formatted text, use the markdown
or html
parameters in Client.send_message()
.
When sending files, the format is appended to the name of the caption
parameter, either caption_markdown
or caption_html
.
Link previews
Link previews are treated as a type of media automatically generated by Telegram. This means you cannot have both a link preview and other media in the same message.
The link_preview
parameter indicates whether link previews are allowed to be present.
If Telegram is unable to generate a link preview for any of the links, there won’t be a link preview.
By default, link previews are not enabled. This is done to prevent sending things you did not explicitly intend to send. Unlike the official clients, which do not have a GUI to “enable” the preview, you can easily enable them from code.
Telegram will attempt to generate a preview for all links contained in the message in order.
You can use this to your advantage, and hide a link to a photo in the first space or invisible character like '\u2063'
.
Note that avid users will be able to find out the link. It is not secret!
Link previews of photos won’t show under the photos of the chat, but it requires a server hosting the image, a public address, and Telegram to be able to generate a preview.
To regenerate a preview, send the corresponding link to @WebpageBot.
Message identifiers
This is an in-depth explanation for how the types.Message.id
works.
Note
You can safely skip this section if you’re not interested.
Every account, whether it’s an user account or bot account, has its own message counter. This counter starts at 1, and is incremented by 1 every time a new message is received. In private conversations or small groups, each account will receive a copy each message. The message identifier will be based on the message counter of the receiving account.
In megagroups and broadcast channels, the message counter instead belongs to the channel itself. It also starts at 1 and is incremented by 1 for every message sent to the group or channel. This means every account will see the same message identifier for a given mesasge in a group or channel.
This design has the following implications:
The message identifier alone is enough to uniquely identify a message only if it’s not from a megagroup or channel. This is why
events.MessageDeleted
does not need to (and doesn’t always) include chat information.Messages cannot be deleted for one-side only in megagroups or channels. Because every account shares the same identifier for the message, it cannot be deleted only for some.
Links to messages only work for everyone inside megagroups or channels. In private conversations and small groups, each account will have their own counter, and the identifiers won’t match.
Let’s look at a concrete example.
You are logged in as User-A.
Both User-B and User-C are your mutual contacts.
You have share a small group called Group-S with User-B.
You also share a megagroup called Group-M with User-C.
Every account and channel has just been created. This means everyone has a message counter of one.
First, User-A will sent a welcome message to both User-B and User-C:
User-A → User-B: Hey, welcome!
User-A → User-C: ¡Bienvenido!
For User-A, “Hey, welcome!” will have the message identifier 1. The message with “¡Bienvenido!” will have an ID of 2.
For User-B, “Hey, welcome” will have ID 1.
For User-B, “¡Bienvenido!” will have ID 1.
Message |
User-A |
User-B |
User-C |
Group-S |
Group-M |
---|---|---|---|---|---|
Hey, welcome! |
1 |
1 |
|||
¡Bienvenido! |
2 |
1 |
Next, User-B and User-C will respond to User-A:
User-B → User-A: Thanks!
User-C → User-A: Gracias :)
Message |
User-A |
User-B |
User-C |
Group-S |
Group-M |
---|---|---|---|---|---|
Hey, welcome! |
1 |
1 |
|||
¡Bienvenido! |
2 |
1 |
|||
Thanks! |
3 |
2 |
|||
Gracias :) |
4 |
2 |
Notice how for each message, the counter goes up by one, and they are independent.
Let’s see what happens when User-B sends a message to Group-S:
User-B → Group-S: Nice group
Message |
User-A |
User-B |
User-C |
Group-S |
Group-M |
---|---|---|---|---|---|
Hey, welcome! |
1 |
1 |
|||
¡Bienvenido! |
2 |
1 |
|||
Thanks! |
3 |
2 |
|||
Gracias :) |
4 |
2 |
|||
Nice group |
5 |
3 |
While the message was sent to a different chat, the group itself doesn’t have a counter. The message identifiers are still unique for each account. The chat where the message was sent can be completely ignored.
Megagroups behave differently:
User-C → Group-M: Buen grupo
Message |
User-A |
User-B |
User-C |
Group-S |
Group-M |
---|---|---|---|---|---|
Hey, welcome! |
1 |
1 |
|||
¡Bienvenido! |
2 |
1 |
|||
Thanks! |
3 |
2 |
|||
Gracias :) |
4 |
2 |
|||
Nice group |
5 |
3 |
|||
Buen grupo |
1 |
The group has its own message counter. Each user won’t get a copy of the message with their own identifier, but rather everyone sees the same message.