Skip to main content

Message Events

Message events represent incoming or outgoing messages in chats, channels, and private conversations.

Message Class

The Message class represents a Telegram message with all its properties and methods.

Properties

message
string
Content of the message
command
string|null
Bot command if present (e.g., “start” from “/start”)
commandType
CommandType|null
Type of bot command
commandArgs
array<string>|null
Bot command arguments if present
protected
bool
Whether this message is protected from forwarding
matches
array<string>|null
Regex matches if a filter regex is present
matchesAll
array|null
All regex matches if a filter multiple match regex is present
media
Media|null
Attached media (Audio, Document, Photo, Video, Voice, Sticker, etc.)
fromScheduled
bool
Whether this is a sent scheduled message
viaBotId
int|null
ID of the bot that generated the message (for inline queries)
editDate
int|null
Last edit date of the message (Unix timestamp)
editHide
bool
Whether the edit is hidden (non-content changes like reactions)
keyboard
InlineKeyboard|ReplyKeyboard|null
Inline or reply keyboard attached to the message
imported
bool
Whether message was imported from a foreign chat service
psaType
string|null
For Public Service Announcement messages, the PSA type
views
int|null
View counter for channel messages
forwards
int|null
Forward counter for channel messages
signature
string|null
Author signature if enabled for channel messages
entities
array<MessageEntity>
Message entities for styled text (bold, italic, links, etc.)
groupedId
int|null
Group ID for albums (all messages in same album have identical ID)
poll
AbstractPoll|null
The poll attached to the message
fwdInfo
ForwardedInfo|null
Information about forwarded message
reactions
array<int|string>
List of our message reactions
scheduled
bool
Whether this is a scheduled message

Handling Messages

Basic Handler

use danog\MadelineProto\EventHandler;
use danog\MadelineProto\EventHandler\Message;

class MyBot extends EventHandler
{
    public function onUpdateNewMessage(Message $message): void
    {
        $text = $message->message;
        $this->logger("Received: $text");
    }
}

With SimpleEventHandler and Filters

use danog\MadelineProto\SimpleEventHandler;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Attributes\Handler;
use danog\MadelineProto\EventHandler\SimpleFilter\Incoming;

class MyBot extends SimpleEventHandler
{
    #[Handler]
    #[Incoming]
    public function handleIncoming(Message $message): void
    {
        // Only processes incoming messages
        $this->logger("Incoming: {$message->message}");
    }
}

Message Methods

reply

Reply to the message.
message
string
required
The message text to send
parseMode
ParseMode
Parse mode for formatting (Markdown, HTML, etc.)
replyMarkup
array
Keyboard markup
noWebpage
bool
default:"false"
Disable link previews
scheduleDate
int
Schedule message for future sending (Unix timestamp)
silent
bool
default:"false"
Send silently (no notification)
$message->reply("Hello! You said: {$message->message}");

// With formatting
$message->reply(
    "**Bold** and _italic_ text",
    parseMode: ParseMode::MARKDOWN
);

// With keyboard
$message->reply("Choose an option:", replyMarkup: [
    'inline_keyboard' => [[
        ['text' => 'Option 1', 'callback_data' => 'opt1'],
        ['text' => 'Option 2', 'callback_data' => 'opt2'],
    ]]
]);

delete

Delete the message.
revoke
bool
default:"true"
Whether to delete for all users (requires permissions)
$message->delete();

edit

Edit the message text.
message
string
required
New message text
parseMode
ParseMode
Parse mode for formatting
replyMarkup
array
New keyboard markup
$message->edit("Updated message text");

forward

Forward the message to another chat.
peer
string|int
required
Destination chat (username or ID)
silent
bool
default:"false"
Send silently
$message->forward('@channel');
$message->forward(123456789);

pin

Pin the message in the chat.
pmOneSide
bool
default:"false"
Whether to pin only for yourself in PM
silent
bool
default:"false"
Pin silently (no notification)
$message->pin();

unpin

Unpin the message.
$message->unpin();

Command Handling

use danog\MadelineProto\EventHandler\Message;

public function onUpdateNewMessage(Message $message): void
{
    if ($message->command === 'start') {
        $message->reply("Welcome!");
    }
    
    if ($message->command === 'echo' && $message->commandArgs) {
        $text = implode(' ', $message->commandArgs);
        $message->reply($text);
    }
}

Media Handling

use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Media\Photo;
use danog\MadelineProto\EventHandler\Media\Document;

public function onUpdateNewMessage(Message $message): void
{
    if ($message->media instanceof Photo) {
        $this->logger("Received a photo");
        // Download the photo
        $info = $message->media->download();
    }
    
    if ($message->media instanceof Document) {
        $this->logger("Received a document: {$message->media->fileName}");
    }
}

Regex Matching

use danog\MadelineProto\SimpleEventHandler;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Filter\FilterRegex;

class MyBot extends SimpleEventHandler
{
    #[FilterRegex('/\/echo (.+)/')]
    public function onEcho(Message $message): void
    {
        $text = $message->matches[1];
        $message->reply($text);
    }
    
    #[FilterRegex('/hello|hi/i')]
    public function onGreeting(Message $message): void
    {
        $message->reply("Hello there!");
    }
}

Entity Processing

use danog\MadelineProto\EventHandler\Message;

public function onUpdateNewMessage(Message $message): void
{
    foreach ($message->entities as $entity) {
        if ($entity->type === 'url') {
            $url = substr($message->message, $entity->offset, $entity->length);
            $this->logger("Found URL: $url");
        }
    }
}

Update Types

New Messages

public function onUpdateNewMessage(Message $message): void
{
    // Handle new messages in private chats and groups
}

New Channel Messages

public function onUpdateNewChannelMessage(Message $message): void
{
    // Handle new messages in channels
}

Edited Messages

public function onUpdateEditMessage(Message $message): void
{
    // Handle edited messages
    $this->logger("Message edited at: {$message->editDate}");
}

Edited Channel Messages

public function onUpdateEditChannelMessage(Message $message): void
{
    // Handle edited channel messages
}

Complete Example

use danog\MadelineProto\SimpleEventHandler;
use danog\MadelineProto\EventHandler\Message;
use danog\MadelineProto\EventHandler\Attributes\Handler;
use danog\MadelineProto\EventHandler\SimpleFilter\{Incoming, HasMedia};
use danog\MadelineProto\EventHandler\Filter\FilterRegex;
use danog\MadelineProto\ParseMode;

class EchoBot extends SimpleEventHandler
{
    #[FilterRegex('/^\/start/')]
    #[Incoming]
    public function handleStart(Message $message): void
    {
        $message->reply(
            "**Welcome to Echo Bot!**\n\n" .
            "Commands:\n" .
            "/echo <text> - Echo your message\n" .
            "/info - Get message info",
            parseMode: ParseMode::MARKDOWN
        );
    }
    
    #[FilterRegex('/^\/echo (.+)/')]
    public function handleEcho(Message $message): void
    {
        $text = $message->matches[1];
        $message->reply($text);
    }
    
    #[FilterRegex('/^\/info/')]
    public function handleInfo(Message $message): void
    {
        $info = [
            "Message ID: {$message->id}",
            "From: {$message->senderId}",
            "Date: " . date('Y-m-d H:i:s', $message->date),
        ];
        
        if ($message->editDate) {
            $info[] = "Edited: " . date('Y-m-d H:i:s', $message->editDate);
        }
        
        $message->reply(implode("\n", $info));
    }
    
    #[Handler]
    #[HasMedia]
    public function handleMedia(Message $message): void
    {
        $type = get_class($message->media);
        $message->reply("Received media: " . basename($type));
    }
}

EchoBot::startAndLoopBot('bot.madeline', 'YOUR_BOT_TOKEN');

See Also

Build docs developers (and LLMs) love