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

Sending Messages

Basic send

#![allow(unused)]
fn main() {
// By username
client.send_message("@username", "Hello!").await?;

// To yourself (Saved Messages)
client.send_message("me", "Note to self").await?;
client.send_to_self("Quick note").await?;

// By numeric ID
client.send_message(123456789_i64, "Hi").await?;
}

send_message accepts anything that implements Into<PeerRef> as the peer (username string, numeric ID, or resolved tl::enums::Peer). The second argument accepts anything that implements Into<InputMessage>, including a bare &str or String for plain text.


Rich messages with InputMessage

InputMessage gives full control over formatting, entities, reply markup, and more:

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

// Plain text
client.send_message("@peer", InputMessage::text("Hello!")).await?;

// Markdown-formatted
client.send_message("@peer", InputMessage::markdown("**Bold** and _italic_ and `code`")).await?;

// HTML-formatted (requires `html` feature)
client.send_message("@peer", InputMessage::html("Hello <b>world</b>")).await?;

// Reply to a message
let msg = InputMessage::text("This is a reply").reply_to(Some(original_id));
client.send_message("@peer", msg).await?;

// Silent message (no notification)
let msg = InputMessage::text("Quiet update").silent(true);
client.send_message("@peer", msg).await?;
}

Message shorthands on IncomingMessage

Every received message exposes shorthand methods that embed the client:

#![allow(unused)]
fn main() {
// Quote-reply in the same chat
msg.reply(InputMessage::text("Got it!")).await?;

// Send to the same chat without quoting
msg.respond("Noted.").await?;

// Edit the message
msg.edit(InputMessage::text("Updated!")).await?;

// Forward to another chat
msg.forward_to("@other_chat").await?;

// Delete
msg.delete().await?;

// Pin / unpin
msg.pin().await?;
msg.unpin().await?;

// Mark as read
msg.mark_read().await?;

// Reload from server
msg.refetch().await?;

// Fetch the message being replied to
if let Some(parent) = msg.get_reply().await? {
    println!("Replied to: {}", parent.text().unwrap_or(""));
}
}

All of these have explicit _with(client, ...) variants for use outside handler closures.


Inline keyboards with InputMessage

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

let kb = InlineKeyboard::new()
    .row([
        Button::callback("✅ Yes", b"yes"),
        Button::callback("❌ No",  b"no"),
    ]);

let msg = InputMessage::text("Confirm?").reply_markup(kb);
client.send_message("@peer", msg).await?;
}

Clicking inline buttons

Three targeting modes via ButtonFilter:

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

// By position (row, col - 0-based)
msg.click_button(ButtonFilter::Pos(0, 0)).await?;

// By exact button label
msg.click_button(ButtonFilter::Text("✅ Yes")).await?;

// By callback data bytes
msg.click_button(ButtonFilter::Data(b"action:buy")).await?;

// By arbitrary predicate
msg.click_button_where(|text, data| text.starts_with("✅")).await?;
}

find_button and find_button_where return Option<(row, col)> without sending anything.


Edit, forward, delete, pin (standalone client methods)

#![allow(unused)]
fn main() {
// Edit by message ID
client.edit_message("@peer", msg_id, InputMessage::text("New text")).await?;

// Forward messages
client.forward_messages("@source", &[id1, id2], "@dest").await?;

// Delete messages (revoke = remove for everyone)
client.delete_messages(&[msg_id_1, msg_id_2], true).await?;

// Pin / unpin
client.pin_message("@peer", msg_id).await?;
client.pin_message("@peer", msg_id, false).await?;
client.unpin_all_messages("@peer").await?;

// Get pinned message
let pinned = client.get_pinned_message("@peer").await?;

// Mark as read
client.mark_read("@peer").await?;

// Export a permanent message link
let link = client.export_message_link("@peer", msg_id).await?;

// Who has read a message (groups/channels with read receipts)
let readers = client.get_message_read_participants("@peer", msg_id).await?;
}

Fetch message history

#![allow(unused)]
fn main() {
// get_message_history(peer, limit, offset_id)
// offset_id = 0 starts from the newest
let messages = client.get_message_history("@peer", 50, 0).await?;

for msg in messages {
    println!("{}: {}", msg.id(), msg.text().unwrap_or(""));
}

// Lazy iterator (auto-paginating)
let mut iter = client.iter_messages("@peer");
while let Some(msg) = iter.next(&client).await {
    println!("{}", msg.text().unwrap_or(""));
}
}

Scheduled messages

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

// Schedule at a Unix timestamp
let msg = InputMessage::text("Happy New Year!").schedule_date(Some(1735689600));
client.send_message("@peer", msg).await?;

// Schedule to send when the recipient comes online
let msg = InputMessage::text("Hey!").schedule_once_online();
client.send_message("@peer", msg).await?;

// List scheduled messages
let scheduled = client.get_scheduled_messages("@peer").await?;

// Send a scheduled message immediately
client.send_scheduled_now("@peer", &[scheduled_id]).await?;

// Cancel a scheduled message
client.delete_scheduled_messages("@peer", &[scheduled_id]).await?;
}

Drafts

#![allow(unused)]
fn main() {
// Save or update a draft
client.save_draft("@peer", "Draft text").await?;

// Trigger server push of all drafts as update events
client.sync_drafts().await?;

// Delete all drafts
client.clear_all_drafts().await?;
}