DM a specific user in discord.py

Viewed 652

I'd like to know how to dm a specific person that will always be the same. I've tried many StackOverFlow posts and the official discord.py documentation but none of them worked. I have discord.py 1.7.3. So far I've got the following:

import discord
from discord.ext import commands

@client.command()
async def dm(ctx):
    user = client.get_user(1234567891011) # <- This user will always be the same.
    await user.send("Hi")

When I type the command in the server the following exception appears:

Ignoring exception in command dm:
Traceback (most recent call last):
  File "C:\Users\myuser\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 85, in wrapped
    ret = await coro(*args, **kwargs)
  File "c:\Users\myuser\Documents\Python Scripts\Bot\main.py", line 110, in dm    await user.send("Hola")
AttributeError: 'NoneType' object has no attribute 'send'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "C:\Users\myuser\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\bot.py", line 939, in invoke
    await ctx.command.invoke(ctx)
  File "C:\Users\myuser\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 863, in invoke
    await injected(*ctx.args, **ctx.kwargs)
  File "C:\Users\myuser\AppData\Local\Programs\Python\Python39\lib\site-packages\discord\ext\commands\core.py", line 94, in wrapped
    raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: AttributeError: 'NoneType' object has no attribute 'send'
4 Answers

The client.get_user-method operates on the local user cache. So unless you already cached the user you want to dm (for example by sharing a server with them and having Intents.members enabled), you will not have them in your local cache and therefore the get_user-method will return None.

To have it working independent of your local user cache, you can use client.fetch_user instead. It will fetch the user by their id from the discord API and thus always return an user object (assuming the given id exists).

Using client.fetch_user, your command could look like this:

@bot.command()
async def dm(ctx):
    user = await client.fetch_user(1234567891011)
    await user.send('Hi')

This implementation allows for any member of the guild to simply type !dm in any channel, and the bot will message the user-specified in client.get_user(<user ID>) a message

import discord
import os
from discord.ext import commands

# Declaration Discord.py Variables
intents = discord.Intents.default()  # Turns on the connection
intents.members = True  # Ensures the member list will be updated properly
client = commands.Bot(command_prefix='!', intents=intents)  # defines the symbol used to call a command from the bot


@client.command()
async def dm(ctx):
    """
    Sends a message to a user every time a member types '!dm' in the channel.
    :param ctx: represents the context in which a command is being invoked under
    :return: a message to the user
    """
    await client.get_user(470163626083352577).send("Enter Text")

client.run("Bot_Token")
  • Here is some more information about how intents work Privileged Intents as you will need Server Member Intent activated.

Bot.get_user() looks up in the client's internal cache. if the user isn't found in cache, This method returns None.

Note that if get_user is returning None, Chances are that user doesn't share a guild with the bot so you cannot DM that user.

You can optionally try to fetch user but you still won't be able to DM the user unless you share a guild with user.

user = await client.fetch_user(id)
await user.send('Message')

This would raise discord.NotFound if user isn't found or discord.Forbidden if you can't DM the user.

Make sure the id is integer.

The error coming is because you have to create a dm in a variable before sending the message

try this:

import discord
from discord.ext import commands

client = commands.Bot(command_prefix='!') 

@client.command()
async def dm(ctx,member:discord.Member,*,content):
    channel = await member.create_dm() #create dm
    await channel.send(content)  #send the message

Edit: In this new code when u run the command !dm <@user> [message] the bot will create a new a dm named channel(note: channel name is just a variable it won't name the dm channel) and then send the message you added at last added

Note: the user must be in the server from where you are sending the dm.

Related