Discord.py rewrite Modmail System

Viewed 3138

Pretty much I am trying to make a modmail bot for a server. Here is the code.

@client.event
async def on_message(message):
    modmail_channel = discord.utils.get(client.get_all_channels(), name="bot-log")

    if message.author == client.user:
        return
    if str(message.channel.type) == "private":
        embed = discord.Embed(color=0x00FFFF)
        embed.set_author(name=f"Olympia Gaming Modmail System", icon_url="https://cdn.discordapp.com/icons/690937143522099220/34fbd058360c3d4696848592ff1c5191.webp?size=1024")
        embed.add_field(name='Report a member:', value=f"React with 1️⃣ if you want to report a member.")        
        embed.add_field(name='Report a Staff Member:', value=f"React with 2️⃣ if you want to report a Staff Member.")    
        embed.add_field(name='Warn Appeal:', value=f"React with 3️⃣ if you would like to appeal a warning.")
        embed.add_field(name='Question:', value=f"React with 4️⃣ if you have a question about our moderation system or the server rules.")
        embed.set_footer(text="Olympia Gaming | Modmail")
        msg = await message.author.send(embed=embed)
        await msg.add_reaction("1️⃣")
        await msg.add_reaction("2️⃣")
        await msg.add_reaction("3️⃣")
        await msg.add_reaction("4️⃣")
    def check(reaction, user):
       return user == message.author and str(reaction.emoji) in ["1️⃣", "2️⃣", "3️⃣", "4️⃣"]


    while True:
        try:
            reaction, user = await client.wait_for("reaction_add", timeout=60, check=check)

            if str(reaction.emoji) == "1️⃣":
                embed = discord.Embed(color=0x00FFFF)
                embed.set_author(name=f"Olympia Gaming Modmail System", icon_url="https://cdn.discordapp.com/icons/690937143522099220/34fbd058360c3d4696848592ff1c5191.webp?size=1024")
                embed.add_field(name='How to Report:', value="Send the ID of the person you are reporting and attach add a screen shot of them breaking a rule (can be ToS or a server rule).")        
                embed.set_footer(text="Olympia Gaming | Report a member ")
                await message.author.send(embed=embed)
                message, user = await client.wait_for("on_message", timeout=60, check=check)
                embed = discord.Embed(title=f"{message.content}", color=0x00FFFF)
                await modmail_channel.send(embed=embed)

               
        except asyncio.TimeoutError:
            await message.delete()
            break

The only problem with this code is it will not send the message to the modmail channel, and it keeps on repeating the original message. Can someone explain how I could fix this?

1 Answers

I have a couple of recommendations for you.

First off, I highly recommend having the following be the very first statement in your on_message:

if message.guild:
    return

This will replace your if str(message.channel.type) == "private":, and ensure that any messages not sent in a DM are immediately discarded.

Second, I suggest using get_channel instead of your discord.utils.get(client.get_all_channels(), name="bot-log") which will search every channel your bot is in until it finds one with the name bot-log. This is inefficient.

Now, the reason your bot will send the initial message every time is because the main on_message will be called any time a message is sent to the bot. You will need to keep track of what users have already gotten sent the initial message so you don't send it again. The simplest implementation of this is just a list that you add user IDs to, and check that list in the main on_message.

Also, your second wait_for will not work, it should just be "message" and you are using your first check function, which is looking for a reaction.

This is a lot all at once, so here is my full on_message with all the changes, hopefully you don't just copy paste it without learning anything:

sent_users = []

@client.event
async def on_message(message):
    if message.guild: # ensure the channel is a DM
        return

    if message.author == client.user:
        return

    if message.author.id in sent_users: # Ensure the intial message hasn't been sent before
        return

    modmail_channel = client.get_channel(CHANNEL_ID)

    embed = discord.Embed(color=0x00FFFF)
    embed.set_author(name=f"Olympia Gaming Modmail System", icon_url="https://cdn.discordapp.com/icons/690937143522099220/34fbd058360c3d4696848592ff1c5191.webp?size=1024")
    embed.add_field(name='Report a member:', value=f"React with 1️⃣ if you want to report a member.")
    embed.add_field(name='Report a Staff Member:', value=f"React with 2️⃣ if you want to report a Staff Member.")
    embed.add_field(name='Warn Appeal:', value=f"React with 3️⃣ if you would like to appeal a warning.")
    embed.add_field(name='Question:', value=f"React with 4️⃣ if you have a question about our moderation system or the server rules.")
    embed.set_footer(text="Olympia Gaming | Modmail")
    msg = await message.author.send(embed=embed)
    await msg.add_reaction("1️⃣")
    await msg.add_reaction("2️⃣")
    await msg.add_reaction("3️⃣")
    await msg.add_reaction("4️⃣")

    sent_users.append(message.author.id) # add this user to the list of sent users

    try:
        def check(reaction, user):
            return user == message.author and str(reaction.emoji) in ["1️⃣", "2️⃣", "3️⃣", "4️⃣"]

        reaction, user = await client.wait_for("reaction_add", timeout=60, check=check)

        if str(reaction.emoji) == "1️⃣":
            embed = discord.Embed(color=0x00FFFF)
            embed.set_author(name=f"Olympia Gaming Modmail System", icon_url="https://cdn.discordapp.com/icons/690937143522099220/34fbd058360c3d4696848592ff1c5191.webp?size=1024")
            embed.add_field(name='How to Report:', value="Send the ID of the person you are reporting and attach add a screen shot of them breaking a rule (can be ToS or a server rule).")
            embed.set_footer(text="Olympia Gaming | Report a member ")
            await message.author.send(embed=embed)

            message = await client.wait_for("message", timeout=60, check=lambda m: m.channel == message.channel and m.author == message.author)
            embed = discord.Embed(title=f"{message.content}", color=0x00FFFF)
            await modmail_channel.send(embed=embed)


    except asyncio.TimeoutError:
        await message.delete()
Related