Discord bot on_join_guild dm everyone - python

I am trying to dm everyone in the server when the bot is added to the server using the on_join_guild().
The code for it
#client.event
async def on_guild_join(guild):
for member in guild.members:
await member.create_dm()
embedVar = discord.Embed(title="Hi", description="Hello", color=0x00ff00)
await member.dm_channel.send(embed=embedVar)
But whenever I add the bot to server, it dms everyone in the server which is expected but a error also pops in the console.
Ignoring exception in on_guild_join
Traceback (most recent call last):
File "C:\Users\Khusi\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File ".\time-turner.py", line 42, in on_guild_join
await member.create_dm()
File "C:\Users\Khusi\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\discord\member.py", line 110, in general
return getattr(self._user, x)(*args, **kwargs)
AttributeError: 'ClientUser' object has no attribute 'create_dm'
What am I doing wrong?

After replicating your code, I found that your error only appears to happen if the bot tries to message itself. You would also get an error if your bot attempts to message another bot (Cannot send messages to this user). You can just use pass if your bot can't message a user or if it tries to message itself.
#client.event
async def on_guild_join(ctx):
for member in ctx.guild.members:
try:
await member.create_dm()
embedVar = discord.Embed(title="Hi", description="Hello", color=0x00ff00)
await member.dm_channel.send(embed=embedVar)
except:
pass
If the above still doesn't work, just as NerdGuyAhmad had said, you need to enable intents, at the very least member intents. View this link here: How do I get intents to work?

Related

Discord.py ctx commands not recognised

im fairly new to coding in general and recently started trying to code my own bot. Almost all of the tutorials i have seen use the ctx command however, whenever i use it i get this error:
"NameError: name 'ctx' is not defined"
Here is part of my code that uses the ctx command. The aim is to get it to delete the last 3 messages sent.
#client.event
async def purge(ctx):
"""clear 3 messages from current channel"""
channel = ctx.message.channel
await ctx.message.delete()
await channel.purge(limit=3, check=None, before=None)
return True
#client.event
async def on_message(message):
if message.content.startswith("purge"):
await purge(ctx)
client.run(os.environ['TOKEN'])
Full error:
Ignoring exception in on_message
Traceback (most recent call last):
File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "main.py", line 31, in on_message
await purge(ctx)
NameError: name 'ctx' is not defined
I'm hosting the server on repl.it if that makes any difference and as i said, im pretty new to coding so it's possible i have missed something very obvious, any help is appreciated. ^_^
A fix to that is:
async def purge(message):
await message.delete()
channel = message.channel
await channel.purge(limit=3)
#client.event
async def on_message(message):
if message.content.startswith("purge"):
await purge(message)
The problem is the on_message function uses message and not ctx. Replacing message with ctx wont work because im pretty sure the on_message cant use ctx

AttributeError: 'ClientUser' object has no attribute 'guild_permissions' on Discord.py

I am trying to make a "!invite" command to generate an invite link to the server and send it to the user's DM.
The command works, but I am getting the following error on console:
Ignoring exception in on_message
Traceback (most recent call last):
File "C:\Users\001\Envs\Pix\lib\site-packages\discord\client.py", line 343, in _run_event
await coro(*args, **kwargs)
File "C:\Users\001\PycharmProjects\Testing bot\cogs\invite.py", line 27, in on_message
if ctx.author.guild_permissions.administrator:
AttributeError: 'ClientUser' object has no attribute 'guild_permissions'
Nevertheless, I get the link: My DM screenshot.
How can I fix this error?
Code:
from discord.ext import commands
from var.canais import inviteChannel
class Invite(commands.Cog):
def __init__(self, client):
self.client = client
#commands.command(
name='invite',
pass_context=True
)
async def invite(self, ctx):
invitelink = await ctx.channel.create_invite(
max_uses=1,
unique=True
)
if inviteChannel:
await ctx.message.delete()
await ctx.author.send(f'Invite link: {invitelink}')
#commands.Cog.listener()
async def on_message(self, ctx):
if inviteChannel:
if ctx.author.guild_permissions.administrator:
return
else:
if not ctx.content.startswith('!invite'):
await ctx.delete()
def setup(client):
client.add_cog(Invite(client))
This error is occurring because the on_message event is also called when the bot sends a message, and in your case the bot is sending the message in a dm, therefore it should be a User object (Member objects are guild only), and user objects don't have permissions since they are not inside a server. It's a ClientUser object instead of User which is a special class like User that is unique to the bot. this is a separate class compared to User because this has some special methods that only the bot can use like one for editing the bot's name and more
to fix this just ignore if the message is sent from a bot so the code would be
#commands.Cog.listener()
async def on_message(self, ctx):
if message.author.bot:
return
if inviteChannel:
if ctx.author.guild_permissions.administrator:
return
if not ctx.content.startswith('!invite'):
await ctx.delete()
Here I added if message.author.bot: return so that it stops the function execution if the author is a bot. and I also removed the unnecessary else statement
As the error says:
The line
if ctx.author.guild_permissions.administrator:
throw an AttributeError error because 'ctx.author' (of type ClientUser) does not have guild_permissions attribute.
The error massage also entail that the error was ignored, and so the code proceed without stoping.
I found this
answer that might help you overcome this issue
good luck!

discord.errors.HTTPException: 400 Bad Request (error code: 50006): Cannot send an empty message

I was trying to test if I can basically copy all messages sent to test_copy_channel channel and paste them to test_paste_channel
Though the bot is executing the commands and logging the embed correctly I keep getting an error.
This is the code I'm using:
import discord
import os
from discord.ext import commands
intents = discord.Intents.default()
intents.members = True
bot = commands.Bot(command_prefix=',', intents=intents)
#bot.event
async def on_ready():
global test_paste_channel, test_copy_channel
test_paste_channel = bot.get_channel(868816978293452841)
test_copy_channel = bot.get_channel(808734570283139162)
print('bot is ready')
#bot.event
async def on_message(message):
# if message.author == bot.user:
# return
if message.channel == test_copy_channel:
await test_paste_channel.send(message.content)
print(message.channel)
if message.content.startswith('!test'):
embed_var = discord.Embed(
title= '''title''',
description= '''description''',
color= discord.Color.red()
)
embed_var.set_footer(text='footer')
await message.channel.send(embed=embed_var)
bot.run(os.getenv('TOKEN'))
So what I do is send !test to test_copy_channel so the bot sends the embed then tries to copy my message and the embed
My message goes through fine but when the bot tries to copy the embed I get this error:
Ignoring exception in on_message
Traceback (most recent call last):
⠀⠀File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/client.py", line 343, in _run_event
⠀⠀⠀⠀await coro(*args, **kwargs)
⠀⠀File "main.py", line 25, in on_message
⠀⠀⠀⠀await test_channel.send(message.content)
⠀⠀File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/abc.py", line 1065, in send data = await state.http.send_message(channel.id, content, tts=tts, embed=embed,
⠀⠀File "/opt/virtualenvs/python3/lib/python3.8/site-packages/discord/http.py", line 254, in request
⠀⠀⠀⠀raise HTTPException(r, data)
discord.errors.HTTPException: 400 Bad Request (error code: 50006): Cannot send an empty message
It doesn't seem to stop the command from executing and the code seems to work properly.
As far as I understand, the error is triggered when it tries to copy the embed message that the bot have sent.
I just wanna know why it's triggering this error.
Okay what I think is happening is when you write :!test The !test is triggered in the other channel which in turn triggers the embed to come through the other channel as you have the line if message.content.startswith('!test') which is not channel specific.
However the problem that is occurring is while the on_message event function gets called when the embed gets sent. The embed has no content so when you try send this out in the line await test_channel.send(message.content) The error occurs as the message.content is empty (as an embed is not content).
A cheat way of fixing this is just adding the line if message.content: above the await test_channel.send(message.content) as the embed gets sent through anyways due to !test being sent in the other channel.
Otherwise you should read this post to see how to get embed information out of a message (in brief its embed_content_in_dict = message.embeds[0].to_dict())
Hope this makes sense :).

How to make the bot send a message with a invite link of the guild to a specific channel in my guild whenever it joins a new server?

So basically what I want is whenever my bot joins any guild it should send a message to a particular channel in my server stating that it is invited to a server with its name and if possible also the invite link of that server. I tried a few things but they never really worked.
#client.event
async def on_guild_join(guild):
channel = client.get_channel('736984092368830468')
await channel.send(f"Bot was added to {guild.name}")
It didn't work and throws the following error:
Ignoring exception in on_guild_join
Traceback (most recent call last):
File "C:\Users\Rohit\AppData\Roaming\Python\Python37\site-packages\discord\client.py", line 312, in _run_event
await coro(*args, **kwargs)
File "c:\Users\Rohit\Desktop\discord bots\test bot\main.py", line 70, in on_guild_join
await channel.send(f"Bot was added to {guild.name}")
AttributeError: 'NoneType' object has no attribute 'send'
And I really don't have any idea how to make the bot send invite link of the guild with the guild name.
The reason why you get the 'NoneType' object has no attribute 'send' exception is because your bot failed to find the channel provided.
This line:
channel = client.get_channel('736984092368830468')
Will not work, this is because the channel ID must be an integer, you can try this:
channel = client.get_channel(int(736984092368830468))
If this still does not work, make sure the bot has access to the channel, the channel exists and the ID provided is correct.
Here's how you would get an invite, name and guild icon assuming your bot has the required permissions.
#client.event
async def on_guild_join(guild):
channel = client.get_channel(745056821777006762)
invite = await guild.system_channel.create_invite()
e = discord.Embed(title="I've joined a server.")
e.add_field(name="Server Name", value=guild.name, inline=False)
e.add_field(name="Invite Link", value=invite, inline=False)
e.set_thumbnail(url=guild.icon_url)
await channel.send(embed=e)

welcome/goodbye using discord.py

I'm trying to create a bot that greets a user that joins a server. But make it so that the person is greeted in the server itself rather than as a DM (which most tutorials I've found teach you how to do).
This is what I've come up with so far.
#bot.event
async def on_member_join(member):
channel = bot.get_channel("channel id")
await bot.send_message(channel,"welcome")
but, it doesn't work and instead throws up this error.
Ignoring exception in on_member_join
Traceback (most recent call last):
File "C:\Users\Lenovo\AppData\Local\Programs\Python\Python36\lib\site-
packages\discord\client.py", line 307, in _run_event
yield from getattr(self, event)(*args, **kwargs)
File "C:\Users\Lenovo\Documents\first bot\bot.py", line 26, in
on_member_join
await bot.send_message(channel,"welcome")
File "C:\Users\Lenovo\AppData\Local\Programs\Python\Python36\lib\site-
packages\discord\client.py", line 1145, in send_message
channel_id, guild_id = yield from self._resolve_destination(destination)
File "C:\Users\Lenovo\AppData\Local\Programs\Python\Python36\lib\site-
packages\discord\client.py", line 289, in _resolve_destination
raise InvalidArgument(fmt.format(destination))
discord.errors.InvalidArgument: Destination must be Channel, PrivateChannel,
User, or Object. Received NoneType
You aren't passing the correct id to get_channel, so it's returning None. A quick way to get it would be to call the command
from discord.ext import commands
bot = commands.Bot(command_prefix='!')
#bot.command(pass_context=True)
async def get_id(ctx):
await bot.say("Channel id: {}".format(ctx.message.channel.id))
bot.run("TOKEN")
You could also modify your command to always post in a channel with a particular name on the server that the Member joined
from discord.utils import get
#bot.event
async def on_member_join(member):
channel = get(member.server.channels, name="general")
await bot.send_message(channel,"welcome")
The answer by Patrick Haugh is probably your best bet, but here are a few things to keep in mind.
The Member object contains the guild (server), and the text channels the server contains.
By using member.guild.text_channels you can ensure the channel will exist, even if the server does not have a 'general' chat.
#bot.event
async def on_member_join(member):
channel = member.guild.text_channels[0]
await channel.send('Welcome!')
Try this:
#bot.event
async def on_member_join(member):
channel = discord.utils.get(member.guild.channels, name='the name of the channel')
await channel.send(f'Enjoy your stay {member.mention}!')

Categories