'How to check if a bot can DM a user

If a user has the privacy setting "Allow direct messages from server members" turned off and a discord bot calls

await user.dm_channel.send("Hello there")

You'll get this error:

discord.errors.Forbidden: 403 Forbidden (error code: 50007): Cannot send messages to this user

I would like to check whether I can message a user without sending them a message. Trying to send a message and catching this error does not work for me, because I don't want a message to get sent in the event that the bot is allowed to message.

I have tried this:

print(user.dm_channel.permissions_for(bot).send_messages)

but it always returns True, even if the message is not permitted.

I have also tried this:

channel = await user.create_dm()
if channel is None:
    ...

but unfortunately, it seems that "has permission to message user" and "has permission to create a dm channel" are considered different.

EDIT

To clarify the exact usage since there seems to be a bit of confusion, take this example. There is a server, and 3 users in question: Me, My Bot, and Steve. Steve has "Allow direct messages from server members" checked off.

The bot has a command called !newgame which accepts a list of users and starts a game amongst them, which involves DMing some of the members of the game. Because of Steve's privacy settings, he cannot play the game (since the bot will need to message him). If I do

!newgame @DJMcMayhem @Steve

I'd like to provide a response like:

> I can't start a game with that list of users because @Steve has the wrong privacy settings.

But as far as I know right now, the only way to find out if Steve can play is by first attempting to message every user, which I'd like to avoid.



Solution 1:[1]

Explanation

You can send an invalid message, which would raise a 400 Bad Request exception, to the dm_channel. This can be accomplished by setting content to None, for example.

If it raises 400 Bad Request, you can DM them. If it raises 403 Forbidden, you can't.

Code

async def can_dm_user(user: discord.User) -> bool:
    ch = user.dm_channel
    if ch is None:
        ch = await user.create_dm()

    try:
        await ch.send()
    except discord.Forbidden:
        return False
    except discord.HTTPException:
        return True

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1