メッセージと埋め込み

プレーンテキストだけでなく、Embed(リッチカード)、Attachment(ファイル)、 Reaction を組み合わせて見やすい出力を作る。

送信オプション

await channel.send({
  content: "本文",
  embeds: [embed1, embed2],         // 最大 10 個
  files: [attachment],
  components: [actionRow],
  allowedMentions: { parse: ["users"] },  // メンション制御
  tts: false,
  flags: MessageFlags.SuppressEmbeds,     // URL の自動展開を抑制
})

Embed

import { EmbedBuilder } from "discord.js"

const embed = new EmbedBuilder()
  .setTitle("タイトル")
  .setURL("https://example.com")
  .setDescription("本文(**Markdown** も使える)")
  .setColor(0x5865F2)            // 数値(左の縦帯)
  .setAuthor({ name: "yui540", iconURL: "https://...", url: "https://..." })
  .setThumbnail("https://...")    // 右上の小画像
  .setImage("https://...")        // 大きな画像(下部)
  .setFooter({ text: "Footer", iconURL: "https://..." })
  .setTimestamp()
  .addFields(
    { name: "項目1", value: "値1", inline: true },
    { name: "項目2", value: "値2", inline: true },
    { name: "全幅", value: "値", inline: false },
  )

await channel.send({ embeds: [embed] })

制限

色の指定

setColor数値0xff5733)、配列 [r, g, b]、文字列名 "Red"、enum Colors.Blue

Attachment(ファイル送信)

import { AttachmentBuilder } from "discord.js"

// パスから
const file = new AttachmentBuilder("./image.png").setName("hero.png")

// Buffer から
const buf = Buffer.from("Hello", "utf-8")
const text = new AttachmentBuilder(buf, { name: "note.txt" })

// 説明文(alt テキスト)
file.setDescription("ヒーロー画像")

await channel.send({
  content: "ファイル送ります",
  files: [file, text],
})

Embed 内で Attachment 画像を参照

const file = new AttachmentBuilder("./chart.png")
const embed = new EmbedBuilder()
  .setTitle("月次レポート")
  .setImage("attachment://chart.png")    // attachment: スキーム

await channel.send({ embeds: [embed], files: [file] })

Markdown

Discord は独自 Markdownを解釈する:

メンション

// userMention / roleMention / channelMention ヘルパー
import { userMention, roleMention, time, TimestampStyles } from "discord.js"

const text = `${userMention(user.id)} は ${time(new Date(), TimestampStyles.RelativeTime)} に来た`

allowedMentions(誤メンション防止)

await channel.send({
  content: "@everyone やあ",
  allowedMentions: { parse: [] },     // メンションを発火させない
})

// 特定ユーザーだけ通知
allowedMentions: { users: [USER_ID] }

編集・削除

const sent = await channel.send("元のメッセージ")
await sent.edit("編集後")
await sent.edit({ content: "...", embeds: [...] })

await sent.delete()
await channel.bulkDelete(10)         // 最大 100 件、14日以内のみ

リアクション

await msg.react("👍")
await msg.react("❤️")
await msg.react(customEmoji)         // GuildEmoji でも可

// 削除
await msg.reactions.removeAll()
await msg.reactions.cache.get("👍")?.remove()

// イベント
client.on(Events.MessageReactionAdd, async (reaction, user) => {
  if (reaction.partial) await reaction.fetch()
  if (user.bot) return
  console.log(`${user.tag} が ${reaction.emoji.name} を付けた`)
})

ピン留め・スレッド

await msg.pin()
await msg.unpin()

// スレッド作成
const thread = await msg.startThread({
  name: "議論",
  autoArchiveDuration: 60,    // 分
})
await thread.send("スレッドへようこそ")

ポーリング(Poll)

Discord にネイティブのポール機能がある。

await channel.send({
  poll: {
    question: { text: "好きな色は?" },
    answers: [
      { text: "赤", emoji: "🟥" },
      { text: "青", emoji: "🟦" },
      { text: "緑", emoji: "🟩" },
    ],
    duration: 24,                 // 時間
    allowMultiselect: false,
  },
})

メッセージ取得

const msg = await channel.messages.fetch(MESSAGE_ID)

// 最新 100 件
const messages = await channel.messages.fetch({ limit: 100 })

// ページング
let last: string | undefined
while (true) {
  const batch = await channel.messages.fetch({ limit: 100, before: last })
  if (batch.size === 0) break
  for (const m of batch.values()) { /* 処理 */ }
  last = batch.last()?.id
}

制限

良いメッセージ設計

✓ 本文は短く、詳細は Embed の description に
色を統一(成功=緑、エラー=赤、情報=青 etc)
✓ 長い情報はfields で分割
✓ 画像はthumbnail(小)と image(大)を使い分け
リアクションをUIとして使わない(Button が遥かに良い)