'How to add role by reacting in DM to a bot message
Im trying to make a bot that send me a message with a reaction button, when I click it, give me a role in the server. Im trying to use on_raw_reaction_add event but I cant reach a solution to make it, Im always getting errors at getting guild roles and this stuff.
In this case, guild is none, I dont know what Im doing wrong.
My code:
@client.command()
async def test(ctx):
global member
global message__id
global channel_id
channel_id = (ctx.channel.id)
member = ctx.message.author
embed = discord.Embed(title="Verify your account", color=0x03fc14)
embed.add_field(name=f"Verification!", value=('React to this message to get verified!'), inline=False)
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)
mesg = await member.send(embed=embed)
await mesg.add_reaction("✅")
message__id = mesg.id
print("EXECUTED")
@client.event
async def on_raw_reaction_add(payload):
print("reacted")
print("messageid accepted")
guild = client.get_guild(payload.guild_id)
if guild is not None:
print("messageid accepted")
reactor = payload.guild.get_member(payload.member.id)
role = discord.utils.get(guild.roles, name="Member")
if payload.emoji.name == '✅':
print("emoji accepted")
await reactor.add_roles(role)
EDIT:
I changed my on_raw_reaction_add event:
@client.event
async def on_raw_reaction_add(payload):
print("reacted")
print("messageid accepted")
guild = client.get_guild(payload.guild_id)
if guild is not None:
print("guild not none ")
reactor = payload.guild.get_member(payload.member.id)
role = discord.utils.get(guild.roles, name="Verified")
if payload.emoji.name == '✅':
print("emoji accepted")
await reactor.add_roles(role)
else:
print("guild none")
And this is what happen when I try the method:
First three words are the prints of the bot reacting his own message, the "EXECUTED" is the print of test method and the last three messages. are when I react the bot message
Solution 1:[1]
In this case, I suggest using a wait_for rather than on_raw_reaction_add.
Example, as seen in the docs:
@client.command(aliases=["t"])
async def test(ctx):
embed = discord.Embed(title="Verify your account", color=0x03fc14)
embed.add_field(name=f"Verification!", value=('React to this message to get verified!'), inline=False)
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)
# sends message to command author
mesg = await ctx.author.send(embed=embed)
await mesg.add_reaction("?")
#check if the reactor is the user and if that reaction is the check mark
def check(reaction, user):
return user == ctx.author and str(reaction.emoji) == '?'
try:
#wait for the user to react according to the checks
reaction, user = await client.wait_for('reaction_add', timeout=60.0, check=check)
except asyncio.TimeoutError:
# 60 seconds without reaction
await ctx.send('Timed out')
else:
await ctx.send('?')
docs- https://discordpy.readthedocs.io/en/stable/api.html?highlight=wait_for#discord.Client.wait_for
Solution 2:[2]
async def test(ctx):
global member
global message__id
global channel_id
channel_id = (ctx.channel.id)
member = ctx.message.author
embed = discord.Embed(title="Verify your account", color=0x03fc14)
embed.add_field(name=f"Verification!", value=('React to this message to get verified!'), inline=False)
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)
mesg = await member.send(embed=embed)
await mesg.add_reaction("?")
message__id = mesg.id
print("EXECUTED")
role = get(ctx.guild.roles, id=role id here)
done = False
while done == False:
reaction, user = await client.wait_for(“reaction_add”, check=check)
if user == client.user:
continue
await member.add_roles(role)
done = True
I am pretty sure something like this would work :D
Solution 3:[3]
When you do guild is not None, it will never fire because you are reacting in a DM channel context - where the guild is None. To access the guild information from the DM, you'll need to save it somewhere in the message (or save it yourself internally). Then, you have the guild object and you're able to add roles or do things to it.
@client.command()
async def testrole(ctx):
member = ctx.author
# ...
embed = discord.Embed(title="Verify your account", color=0x03fc14)
embed.add_field(name=f"Verification!", value=('React to this message to get verified!'), inline=False)
embed.set_footer(text=ctx.author, icon_url=ctx.author.avatar_url)
mesg = await member.send(str(ctx.guild.id), embed=embed) # we need the guild information somewhere
await mesg.add_reaction("?")
@client.event
async def on_reaction_add(reaction, user): # there's really no need to use raw event here
if user.id == client.user.id:
return
if reaction.message.guild is None:
if reaction.emoji == '\u2705':
# we have to get the guild that we saved in the other function
# there is no other way to know the guild, since we're reacting in the DM
# that's why it was saved inside of the message that was sent to the user
guild_id = int(reaction.message.content)
guild = client.get_guild(guild_id)
member = guild.get_member(user.id)
await member.add_roles(...) # change this with your roles
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 | |
| Solution 2 | |
| Solution 3 | Eric Jin |

