Messaging

This guide covers all aspects of sending, receiving, and managing messages.

Sending Messages

Basic Message

message = await backend.send_message(
    channel_id="C123456",
    content="Hello, world!",
)

print(f"Sent: {message.id}")

Formatted Message

from chatom.format import FormattedMessage

msg = FormattedMessage()
msg.bold("Important:")
msg.text(" Please read this.")

content = msg.render(backend.get_format())
message = await backend.send_message(
    channel_id=channel.id,
    content=content,
)

Send to Channel by Name

# Look up channel first
channel = await backend.fetch_channel(name="general")

# Then send
message = await backend.send_message(
    channel_id=channel.id,
    content="Hello!",
)

Reading Messages

Message History

# Read last 50 messages
async for message in backend.read_messages(channel_id="C123456", limit=50):
    author = message.author.name if message.author else "Unknown"
    print(f"{author}: {message.content}")

With Pagination

# Read in batches
messages = []
async for message in backend.read_messages(channel_id="C123456", limit=100):
    messages.append(message)

    # Process in batches of 20
    if len(messages) >= 20:
        process_batch(messages)
        messages = []

# Process remaining
if messages:
    process_batch(messages)

Since a Specific Time

from datetime import datetime, timedelta

# Read messages from last hour
since = datetime.now() - timedelta(hours=1)

async for message in backend.read_messages(
    channel_id="C123456",
    after=since,
    limit=100,
):
    print(message.content)

Threads

Create a Thread

# Send parent message
parent = await backend.send_message(
    channel_id="C123456",
    content="📋 Discussion Topic: New Feature",
)

# Reply in thread
reply = await backend.reply_to_message(
    channel_id="C123456",
    message_id=parent.id,
    content="I think we should...",
)

Multiple Replies

# Send several replies
for i, point in enumerate(discussion_points):
    await backend.reply_to_message(
        channel_id="C123456",
        message_id=parent.id,
        content=f"{i+1}. {point}",
    )

Read Thread Messages

# Read all messages in a thread
async for message in backend.read_thread(
    channel=channel,
    thread=parent_message,
    limit=50,
):
    print(f"{message.author.name}: {message.content}")

Direct Messages

Create DM Channel

# Find user
user = await backend.fetch_user(name="Alice")

# Create/open DM channel
dm_channel_id = await backend.create_dm([user.id])

# Send message
await backend.send_message(
    channel=dm_channel_id,
    content="Hello! This is a private message.",
)

Convenience Method

# Send DM directly
message = await backend.send_dm(
    user=user,
    content="Quick question for you!",
)

Reactions

Add Reaction

await backend.add_reaction(
    channel_id="C123456",
    message_id="M789",
    emoji="thumbsup",  # emoji name without colons
)

Multiple Reactions

emojis = ["thumbsup", "rocket", "heart"]

for emoji in emojis:
    await backend.add_reaction(
        channel_id="C123456",
        message_id="M789",
        emoji=emoji,
    )

Remove Reaction

await backend.remove_reaction(
    channel_id="C123456",
    message_id="M789",
    emoji="thumbsup",
)

Unicode Emojis (Discord)

# Discord accepts unicode directly
await backend.add_reaction(
    channel_id="C123456",
    message_id="M789",
    emoji="👍",
)

Editing Messages

# Send initial message
message = await backend.send_message(
    channel_id="C123456",
    content="Processing...",
)

# Do some work...
await asyncio.sleep(2)

# Update the message
await backend.edit_message(
    channel_id="C123456",
    message_id=message.id,
    content="Processing... Done! ✅",
)

Deleting Messages

await backend.delete_message(
    channel_id="C123456",
    message_id="M789",
)

Forwarding Messages

# Forward a message to another channel
await backend.forward_message(
    message=original_message,
    target_channel_id="C789",
)

Listening for Messages

Real-time Events

async for message in backend.listen():
    print(f"New message: {message.content}")

    # Respond to mentions
    if message.mentions_user(backend.bot_user_id):
        await backend.reply_to_message(
            channel_id=message.channel_id,
            message_id=message.id,
            content="You mentioned me!",
        )

With Timeout

import asyncio

async def listen_with_timeout(backend, timeout=60):
    try:
        async with asyncio.timeout(timeout):
            async for message in backend.listen():
                yield message
    except asyncio.TimeoutError:
        print("Listener timed out")

Message Objects

Properties

message = await backend.send_message(channel_id, content)

# Basic info
message.id          # Unique identifier
message.content     # Text content
message.created_at  # When sent
message.edited_at   # When last edited (if any)

# Author
message.author      # User object
message.author_id   # User ID string

# Channel
message.channel     # Channel object
message.channel_id  # Channel ID string

# Threading
message.thread_id   # Parent thread ID
message.reply_to_id # Message being replied to

# Rich content
message.reactions   # List of Reaction objects
message.attachments # List of Attachment objects
message.embeds      # List of Embed objects

Detecting Mentions

# Get all mentioned user IDs
user_ids = message.get_mentioned_user_ids()

# Get all mentioned channel IDs
channel_ids = message.get_mentioned_channel_ids()

# Check if specific user is mentioned
if message.mentions_user("U123456"):
    print("User was mentioned!")

Response Convenience Methods

Messages have convenience methods that construct new Message instances. This makes it easy to create replies, forwards, or quotes:

as_reply(content, **kwargs)

Create a new message as a reply to this message:

async for message in backend.listen():
    if "help" in message.content.lower():
        # Create a reply message
        reply = message.as_reply("I can help with that!")
        # reply.reply_to is message
        # reply.message_type is MessageType.REPLY

as_thread_reply(content, **kwargs)

Create a reply within the existing thread (or create one if not in a thread):

# If message is in a thread, new message is in that thread
# Otherwise, a new thread is created from this message
reply = message.as_thread_reply("Following up on this...")
# reply.thread is set appropriately

as_forward(target_channel, **kwargs)

Create a forwarded message to another channel with attribution:

# Forward to moderation channel
forward = message.as_forward(mod_channel)
# forward.forwarded_from is message
# forward.message_type is MessageType.FORWARD
# forward.content includes "[Forwarded from Alice in #general]\nOriginal content..."

as_quote_reply(content, **kwargs)

Create a reply that quotes the original message:

quote = message.as_quote_reply("I agree with this!")
# quote.content is "> Original message\n\nI agree with this!"

reply_context()

Get context information for custom reply handling:

ctx = message.reply_context()
# Returns: {
#   "channel": Channel(...),
#   "message": Message(...),
#   "thread": Thread(...) or None,
#   "author": User(...),
# }

# Use for custom logic
new_msg = Message(
    channel=ctx["channel"],
    content=f"Replying to {ctx['message'].author_name}",
    reply_to=ctx["message"],
)

Complete Response Bot Example

async for message in backend.listen():
    content = message.content.lower()

    if "!help" in content:
        # Create a reply
        reply = message.as_reply("Available commands: !help, !forward")
        # ... send via your preferred method

    elif "!forward" in content:
        # Forward to log channel
        forward = message.as_forward(log_channel)
        # forward.forwarded_from is message

    elif "!quote" in content:
        # Quote and respond
        quote = message.as_quote_reply("Acknowledged! ✅")

## Error Handling

```python
try:
    message = await backend.send_message(
        channel_id="C123456",
        content="Hello!",
    )
except Exception as e:
    print(f"Failed to send message: {e}")

Complete Example: Notification Bot

import asyncio
from chatom.slack import SlackBackend, SlackConfig
from chatom.format import FormattedMessage, Table

async def daily_report():
    config = SlackConfig(bot_token="xoxb-your-token")
    backend = SlackBackend(config=config)
    await backend.connect()

    try:
        # Get channel
        channel = await backend.fetch_channel(name="reports")

        # Create formatted report
        msg = FormattedMessage()
        msg.heading("📊 Daily Report", level=2)
        msg.paragraph(f"Report generated at {datetime.now()}")

        # Add table
        table = Table.from_data(
            headers=["Metric", "Value", "Change"],
            data=[
                ["Users", "1,234", "+5%"],
                ["Revenue", "$45,678", "+12%"],
                ["Errors", "23", "-8%"],
            ],
        )
        msg.table(table)

        # Send report
        content = msg.render(backend.get_format())
        report_msg = await backend.send_message(
            channel_id=channel.id,
            content=content,
        )

        # Add reaction to indicate success
        await backend.add_reaction(
            channel_id=channel.id,
            message_id=report_msg.id,
            emoji="white_check_mark",
        )

    finally:
        await backend.disconnect()

asyncio.run(daily_report())

Next Steps