Skip to main content
This guide covers everything you need to know about direct messaging, including sending messages, managing conversations, group DMs, and message reactions.

Sending direct messages

Send a DM to a user

message = await client.send_dm(
    user_id='123456789',
    text='Hello! How are you?'
)
print(f'Message sent: {message.id}')

Send a DM with media

Attach images, videos, or GIFs to your direct messages:
# Upload media first
media_id = await client.upload_media('vacation_photo.jpg')

# Send DM with media
message = await client.send_dm(
    user_id='123456789',
    text='Check out this photo!',
    media_id=media_id
)
Unlike tweets, direct messages can only include one media attachment at a time.

Reply to a message

# Get conversation history
history = await client.get_dm_history('123456789')
last_message = history[0]

# Reply to the last message
reply = await client.send_dm(
    user_id='123456789',
    text='Thanks for your message!',
    reply_to=last_message.id
)

Managing DM conversations

Get conversation history

# Get DM history with a specific user
history = await client.get_dm_history('123456789')

for message in history:
    print(f'{message.time}: {message.text}')
    
    # Check for attachments
    if message.attachment:
        print(f'  Has attachment: {message.attachment}')

# Load more messages (older)
more_messages = await history.next()

Using user object for DM history

user = await client.get_user_by_screen_name('example_user')
history = await user.get_dm_history()

for message in history:
    print(f'{message.time}: {message.text}')

# Pagination
more_messages = await history.next()

Message attributes

The Message object provides access to message details:
message = history[0]

print(message.id)              # Message ID
print(message.text)            # Message text
print(message.time)            # Timestamp
print(message.sender_id)       # Sender's user ID
print(message.recipient_id)    # Recipient's user ID
print(message.attachment)      # Attachment data (if any)

Deleting messages

await client.delete_dm('message_id_here')
Deleting a message removes it from the conversation for all participants.

Message reactions

Add emoji reactions to messages in conversations.

Add a reaction

user_id = '123456789'
my_id = await client.user_id()
conversation_id = f'{user_id}-{my_id}'

await client.add_reaction_to_message(
    message_id='message_id_here',
    conversation_id=conversation_id,
    emoji='👍'
)

Remove a reaction

user_id = '123456789'
my_id = await client.user_id()
conversation_id = f'{user_id}-{my_id}'

await client.remove_reaction_from_message(
    message_id='message_id_here',
    conversation_id=conversation_id,
    emoji='👍'
)

Group DMs

Work with group direct message conversations.

Send a message to a group

group_id = '123456789'

message = await client.send_dm_to_group(
    group_id=group_id,
    text='Hello everyone!'
)
print(f'Group message sent: {message.id}')

Send media to a group

media_id = await client.upload_media('group_photo.jpg')

message = await client.send_dm_to_group(
    group_id=group_id,
    text='Check this out!',
    media_id=media_id
)

Get group conversation history

group_id = '123456789'

history = await client.get_group_dm_history(group_id)
for message in history:
    print(f'{message.time}: {message.text}')

# Load more messages
more_messages = await history.next()

Get group information

group = await client.get_group('123456789')

print(f'Group name: {group.name}')
print(f'Created at: {group.created_at}')
print(f'Type: {group.type}')

# Get group participants
for participant in group.participants:
    print(f'Member: {participant.screen_name}')

Add members to a group

group_id = '123456789'
user_ids = ['111111', '222222', '333333']

await client.add_members_to_group(group_id, user_ids)
print('Members added to group')

Change group name

await client.change_group_name(
    group_id='123456789',
    name='New Group Name'
)

Practical examples

Auto-reply bot

Create a simple auto-reply system:
import asyncio

async def auto_reply_bot():
    # Store last checked message ID to avoid duplicates
    last_message_id = None
    
    while True:
        try:
            # Get your DM history
            me = await client.user()
            # You would need to get list of conversations first
            # This is a simplified example
            
            # Check each conversation for new messages
            # and send auto-reply
            
            await asyncio.sleep(60)  # Check every minute
        except Exception as e:
            print(f'Error: {e}')
            await asyncio.sleep(60)

# Run the bot
await auto_reply_bot()
See the examples/dm_auto_reply.py file in the Twikit repository for a complete auto-reply bot implementation.

Send bulk DMs

import asyncio

user_ids = ['123456', '789012', '345678']
message_text = 'Thanks for following!'

for user_id in user_ids:
    try:
        await client.send_dm(user_id, message_text)
        print(f'Sent DM to {user_id}')
        
        # Add delay to respect rate limits
        await asyncio.sleep(2)
    except Exception as e:
        print(f'Failed to send to {user_id}: {e}')
Be careful with bulk DMs. Sending too many messages too quickly may result in rate limiting or account restrictions. Always add delays between messages and ensure you have permission to contact users.

Save conversation history

import json
from datetime import datetime

user_id = '123456789'
all_messages = []

# Fetch all messages
history = await client.get_dm_history(user_id)
while history:
    all_messages.extend(history)
    try:
        history = await history.next()
    except:
        break

# Save to file
conversation_data = [
    {
        'id': msg.id,
        'time': msg.time,
        'text': msg.text,
        'sender_id': msg.sender_id
    }
    for msg in all_messages
]

with open(f'conversation_{user_id}.json', 'w') as f:
    json.dump(conversation_data, f, indent=2)

print(f'Saved {len(all_messages)} messages')

Notification system for new DMs

import asyncio

async def check_new_messages():
    known_messages = set()
    
    while True:
        try:
            # Check DMs from a specific user
            history = await client.get_dm_history('123456789')
            
            for message in history:
                if message.id not in known_messages:
                    print(f'New message: {message.text}')
                    # You could send a notification here
                    known_messages.add(message.id)
            
            await asyncio.sleep(30)  # Check every 30 seconds
        except Exception as e:
            print(f'Error: {e}')
            await asyncio.sleep(30)

await check_new_messages()

Working with message attachments

Handle media attachments in direct messages:
history = await client.get_dm_history('123456789')

for message in history:
    if message.attachment:
        attachment = message.attachment
        
        # Check attachment type
        if 'photo' in attachment:
            photo_url = attachment['photo']['url']
            print(f'Photo: {photo_url}')
        
        elif 'video' in attachment:
            video_url = attachment['video']['url']
            print(f'Video: {video_url}')
        
        # Download attachment
        # You can use client.http to download the file
        response = await client.http.get(photo_url)
        with open(f'attachment_{message.id}.jpg', 'wb') as f:
            f.write(response.content)

Best practices

1

Respect rate limits

Add delays between messages and API calls to avoid rate limiting.
2

Check permissions

Ensure the user can receive DMs (user.can_dm) before attempting to send messages.
3

Handle errors gracefully

Users may have DMs disabled or may have blocked you. Always wrap DM operations in try-except blocks.
4

Keep conversations organized

Use message IDs and timestamps to track conversation state and avoid duplicate processing.

Build docs developers (and LLMs) love