Discord.js机器人无法向指定角色用户批量发送DM问题咨询
问题原因分析
- 触发
Cannot read properties of null (reading 'roles')报错的核心原因是message.guild为null:当消息来自Discord私信通道时,message.guild属性会返回空值,没有对应的roles对象,就会抛出该错误。你之前注释发信代码时运行正常,是因为当时测试的消息都来自服务器通道,没有触发私信场景的异常。 - 原有等待间隔逻辑完全无效:
forEach遍历不会等待异步任务执行完成,所有的sleep(5000)会几乎同时触发,5秒后所有发信请求会批量并发,根本起不到限流防反spam的作用。 - 代码存在细节错误:
message对象上没有users属性,获取用户需要从机器人客户端实例(也就是你代码里的bot)上调用fetch方法。 - 如果你使用的是discord.js v13及以上版本,原来的
message事件已经被官方废弃,改用messageCreate事件,旧事件监听也可能导致异常触发。
可直接运行的实现代码
// Promise版等待函数,用于控制请求间隔 function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } // discord.js v13+ 使用messageCreate事件,v12及以下可改回message bot.on('messageCreate', async message => { // 过滤非服务器消息、非触发指令(可自行修改触发条件) if (!message.guild || !message.content.startsWith('!发角色私信')) return; try { // 获取目标角色 const targetRole = message.guild.roles.cache.find(role => role.id === "替换为你的角色ID"); if (!targetRole) { console.log('未找到指定ID的角色'); return; } // 提取角色下所有用户ID const targetMemberIds = targetRole.members.map(m => m.id); console.log(`共匹配到${targetMemberIds.length}个持有目标角色的用户`); // 遍历发送私信,内置间隔和错误捕获 for (const userId of targetMemberIds) { try { const targetUser = await bot.users.fetch(userId, false); await targetUser.send("替换为你要发送的私信内容"); console.log(`成功向用户${userId}发送私信`); } catch (sendErr) { console.log(`向用户${userId}发送私信失败:${sendErr.message}`); } // 每次发送后等待5秒再执行下一次请求 await sleep(5000); } console.log('所有私信任务执行完成'); } catch (globalErr) { console.log('全局执行错误:', globalErr.message); } });
注意事项
- 批量发送私信属于高风险操作,非常容易被Discord判定为spam,除了添加请求间隔外,建议单次遍历的用户数量不要超过50,也不要高频触发该功能。
- 发信逻辑必须添加错误捕获:部分用户会关闭陌生人私信权限,发送请求会失败,不捕获异常会导致整个机器人程序崩溃。
- 需要在Discord开发者后台给机器人开启
Server Members Intent权限,否则机器人无法拉取完整的服务器成员列表,角色下的成员缓存会缺失。 - 若服务器成员数超过100,建议先主动拉取全量成员缓存,避免因缓存不全导致漏发用户。
内容的提问来源于stack exchange,提问作者JamesG
相关产品推荐
相关产品推荐

