How to send a message with discord.py without a command

60,320

Solution 1

The reason your code is not working is because client.run is blocking, meaning that nothing after it will execute. This means your loop will never be reached.

To get around this, use client.loop.create_task.

The github of discord.py has an example of a background task, found here. You should be able to use this as reference. Currently the task posts a message to the given channel every minute, but you can easily modify it to wait for a specific action.

New discord.py versions

import discord
import asyncio

client = discord.Client()

async def my_background_task():
    await client.wait_until_ready()
    counter = 0
    channel = client.get_channel(id=123456789) # replace with channel_id
    while not client.is_closed():
        counter += 1
        await channel.send(counter)
        await asyncio.sleep(60) # task runs every 60 seconds

@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')

client.loop.create_task(my_background_task())
client.run('token')

Older discord.py versions

import discord
import asyncio

client = discord.Client()

async def my_background_task():
    await client.wait_until_ready()
    counter = 0
    channel = discord.Object(id='channel_id_here')
    while not client.is_closed:
        counter += 1
        await client.send_message(channel, counter)
        await asyncio.sleep(60) # task runs every 60 seconds

@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('------')

client.loop.create_task(my_background_task())
client.run('token')

Solution 2

For responsive behaviour, you have two options: you can write a on_message event handler, or use the discord.ext.commands module. I recommend using commands, as it's more powerful and doesn't keep everything in a single coroutine.

from discord.ext.commands import Bot

bot = Bot(command_prefix='!')

@bot.event
async def on_ready():
    print("I'm ready.")
    global target_channel
    target_channel = bot.get_channel("412678093006831617")

@bot.command()
async def send(*, message):                         
    global target_channel
    await bot.send_message(channel, message)

This would be called with !send Some message. The *, message syntax just tells the bot not to try and parse the message contents further.

Share:
60,320
mauexe
Author by

mauexe

Updated on November 12, 2021

Comments

  • mauexe
    mauexe over 2 years
    import discord
    import asyncio
    
    client = discord.Client()
    @client.event
    async def on_ready():
        print("I'm ready.")
    
    async def send(message):
        await client.send_message(client.get_channel("123456789"), message)
    
    client.run("token")
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(send("hello"))
    

    Hi, i want to make a GUI. When someone put in his name and press "OK" my discord bot should send a message. Basically i thought i call the async by it's name, didn't work. Then i made a event loop. worked with a print(), but the bot doesn't send a message, so i thought it is not ready, when i put wait_until_ready() there it executed nothing, so i thought i have to put the client.run("token") before the event loop, didn't work either.

    can you guys help me? :)

  • Benjin
    Benjin about 6 years
    Would you be able to call the command from the GUI? Curious as I have not experimented with something like that
  • Patrick Haugh
    Patrick Haugh about 6 years
    Do you want to send the message from wherever you're running the bot from, or from discord? I'm not sure what GUI you're talking about.
  • Benjin
    Benjin about 6 years
    LordSquiddy is asking how to make a bot respond after you press OK on a GUI
  • mauexe
    mauexe about 6 years
    @Benjin is right, i would like to send a message when i click OK on a GUI, not from discord.
  • F.M
    F.M over 3 years
    Does this still work? I tried it and it didn't send anything
  • Benjin
    Benjin over 3 years
    @F.M This is outdated as it uses an older version of discord.py, referred to as the async branch. Things like client.send_message don't exist in the newer versions. You need to use await channel.send() now. See example here.
  • F.M
    F.M over 3 years
    Thanks for the response! I'll check it out
  • alper
    alper almost 3 years
    How could I run def send ?
  • alper
    alper almost 3 years
    *** AttributeError: 'Client' object has no attribute 'send_message'
  • Benjin
    Benjin almost 3 years
    @alper send_message will only work on older versions of discord.py, referred to as the async branch. On the new version, you can use await channel.send(counter)
  • alper
    alper almost 3 years
    It should also be channel = client.get_channel(id='channel_id_here')
  • Benjin
    Benjin almost 3 years
    @alper thanks for catching that! Feel free to edit answers if you find other mistakes
  • Boris Verkhovskiy
    Boris Verkhovskiy almost 3 years
    I think also while not client.is_closed: should be while not client.is_closed(): because it looks like it's a function
  • Boris Verkhovskiy
    Boris Verkhovskiy almost 3 years
    I think the correct link to the example is now github.com/Rapptz/discord.py/blob/master/examples/… the branch you link to/copy-pasted from is really old