2

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'
Daniel Walker
  • 6,380
  • 5
  • 22
  • 45
jgames07
  • 48
  • 1
  • 9

4 Answers4

3

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')
502E532E
  • 431
  • 2
  • 11
0

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.
yet-it-compiles
  • 108
  • 1
  • 10
  • I am not quite sure why this is the accepted answer, because in my opinion (as well as in my tests) it does not solve the problem. Some problems I see: The code seems to be the same as in the question, just compressed into a single line. The `await` should not do anything since `client.get_user` is not a coroutine. It will just raise an exception. When the user is not in the local user cache, `client.get_user` will return None and it will lead to an exception. If it succeded in your tests, please correct me, otherwise this answer should be revised or a working one should be accepted. – 502E532E Aug 30 '21 at 20:48
  • Yeah actually the answer wasn't the problem, but the bot itself, I'll edit it in the upper part of the post if I can. I marked it as accepted because the guy from the answer reached out to me and helped me for about half an hour until it worked. – jgames07 Aug 30 '21 at 20:56
  • Okay, it's nice that it is working now. I think it would be even better if you could suggest an edit to yet-it-compiles (or ask them to edit their answer) so it contains the code that is working for you now (and maybe add some explaination on what the error was). This way, future visitors of this question will know what you did to solve your problem and are able to profit from your question as well. With accepting an answer you not only show that your problem got solved, but also how you solved it, so it is quite important that the solution is actually working for you. – 502E532E Aug 30 '21 at 21:11
  • I changed the post so that it says at the top that both answers work. I think that yet-it-compiles is just a simplified answer from mine, so it should also work. – jgames07 Aug 30 '21 at 23:19
  • The above method doesn't raise any exceptions @502E532E, and was an alternative solution to OP post. However, I am open to any ways that I may modify this accepted solution to improve it for future readers. – yet-it-compiles Aug 31 '21 at 06:28
  • @yet-it-compiles do you do some relevant things in your surrounding code (e.g. enabling the members intent)? Because if I copy-paste the method into my bot, I get `AttributeError: 'NoneType' object has no attribute 'send'`. – 502E532E Aug 31 '21 at 15:13
  • With added user caching it should be fine. I was wrong regarding the `await`, of course `user.send` is a coroutine and it is needed. I'm sorry for this. – 502E532E Aug 31 '21 at 15:17
  • @502E532E it's all good! I greatly appreciate your comments. I have also updated the code with everything necessary to run it. – yet-it-compiles Sep 01 '21 at 23:34
  • 1
    @yet-it-compiles I believe it should work now, thank you for updating! – 502E532E Sep 02 '21 at 10:44
0

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.

NikoX
  • 127
  • 8
-1

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.