Skip to content

Sending Messages

The basic feature of Discord Bots is sending messages across Discord. That’s why here we will see how to send messages with Seyfert.

First of all, we need to set up a basic Hello World command.

src/commands/helloworld.ts
import {
class Command
Command
,
function Declare(declare: CommandDeclareOptions): <T extends {
new (...args: any[]): object;
}>(target: T) => {
new (...args: any[]): {
name: string;
nsfw: boolean | undefined;
props: ExtraProps | undefined;
contexts: InteractionContextType[];
integrationTypes: ApplicationIntegrationType[];
defaultMemberPermissions: bigint | undefined;
botPermissions: bigint | undefined;
description: string;
type: ApplicationCommandType;
guildId?: string[];
ignore?: IgnoreCommand;
aliases?: string[];
handler?: EntryPointCommandHandlerType;
};
} & T
Declare
, type
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
} from 'seyfert';
@
function Declare(declare: CommandDeclareOptions): <T extends {
new (...args: any[]): object;
}>(target: T) => {
new (...args: any[]): {
name: string;
nsfw: boolean | undefined;
props: ExtraProps | undefined;
contexts: InteractionContextType[];
integrationTypes: ApplicationIntegrationType[];
defaultMemberPermissions: bigint | undefined;
botPermissions: bigint | undefined;
description: string;
type: ApplicationCommandType;
guildId?: string[];
ignore?: IgnoreCommand;
aliases?: string[];
handler?: EntryPointCommandHandlerType;
};
} & T
Declare
({
name: string
name
: 'helloworld',
description: string
description
: 'Sends a basic hello world message.',
})
export default class
class HelloWorldCommand
HelloWorldCommand
extends
class Command
Command
{
async
HelloWorldCommand.run(ctx: CommandContext): Promise<void>
run
(
ctx: CommandContext<{}, never>
ctx
:
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
) {}
}

Having set up our basic Hello World command, we are now ready to send our first message using the CommandContext.write() function.

src/commands/helloworld.ts
import {
class Command
Command
,
function Declare(declare: CommandDeclareOptions): <T extends {
new (...args: any[]): object;
}>(target: T) => {
new (...args: any[]): {
name: string;
nsfw: boolean | undefined;
props: ExtraProps | undefined;
contexts: InteractionContextType[];
integrationTypes: ApplicationIntegrationType[];
defaultMemberPermissions: bigint | undefined;
botPermissions: bigint | undefined;
description: string;
type: ApplicationCommandType;
guildId?: string[];
ignore?: IgnoreCommand;
aliases?: string[];
handler?: EntryPointCommandHandlerType;
};
} & T
Declare
, type
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
} from 'seyfert';
@
function Declare(declare: CommandDeclareOptions): <T extends {
new (...args: any[]): object;
}>(target: T) => {
new (...args: any[]): {
name: string;
nsfw: boolean | undefined;
props: ExtraProps | undefined;
contexts: InteractionContextType[];
integrationTypes: ApplicationIntegrationType[];
defaultMemberPermissions: bigint | undefined;
botPermissions: bigint | undefined;
description: string;
type: ApplicationCommandType;
guildId?: string[];
ignore?: IgnoreCommand;
aliases?: string[];
handler?: EntryPointCommandHandlerType;
};
} & T
Declare
({
name: string
name
: 'helloworld',
description: string
description
: 'Sends a basic hello world message.',
})
export default class
class HelloWorldCommand
HelloWorldCommand
extends
class Command
Command
{
async
HelloWorldCommand.run(ctx: CommandContext): Promise<void | WebhookMessage>
run
(
ctx: CommandContext<{}, never>
ctx
:
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
) {
return
ctx: CommandContext<{}, never>
ctx
.
CommandContext<{}, never>.write<false>(body: InteractionCreateBodyRequest, withResponse?: false | undefined): Promise<void | WebhookMessage>
write
({
content?: string | undefined

The message contents (up to 2000 characters)

content
: 'Hello world 👋' });
}
}

The CommandContext.write() function will respond to the command.

EditOrReply

But what if we want to respond to the command or edit its response instead of just replying?

We can use the CommandContext.editOrReply() function. This function is used to reply to the command, or if a reply has already been sent, it will edit it.

This function is very useful if we want to develop a command that responds to the command or, if the command has been answered, edits the response. If we are only using a simple CommandContext.write(), a response will be sent in all cases.

Here’s an example of how to implement this function.

src/commands/helloworld.ts
import {
class Command
Command
, type
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
} from 'seyfert';
export default class
class HelloWorldCommand
HelloWorldCommand
extends
class Command
Command
{
async
HelloWorldCommand.run(ctx: CommandContext): Promise<void>
run
(
ctx: CommandContext<{}, never>
ctx
:
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
) {
await
ctx: CommandContext<{}, never>
ctx
.
CommandContext<{}, never>.deferReply<false>(ephemeral?: boolean, withResponse?: false | undefined): Promise<undefined>
deferReply
();
// do something that takes time and is boring
await
ctx: CommandContext<{}, never>
ctx
.
CommandContext<{}, never>.editOrReply<false>(body: InteractionCreateBodyRequest | InteractionMessageUpdateBodyRequest, withResponse?: false | undefined): Promise<...>
editOrReply
({
content: string
content
: 'I did some stuff' });
}
}

Sending Messages Without a Response

While reading this guide, you may have thought about the possibility of simply sending a message to a channel instead of responding to a command.

Here we are. To send a simple message to a specific channel, we need to get its ID and then access the BaseClient.messages property and use the write function.

Here’s an example of how to send that message without replying to a command:

src/commands/helloworld.ts
import {
class Command
Command
, type
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
} from 'seyfert';
export default class
class HelloWorldCommand
HelloWorldCommand
extends
class Command
Command
{
async
HelloWorldCommand.run(ctx: CommandContext): Promise<Message>
run
(
ctx: CommandContext<{}, never>
ctx
:
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
) {
return
ctx: CommandContext<{}, never>
ctx
.
CommandContext<{}, never>.client: UsingClient
client
.
BaseClient.messages: MessageShorter
messages
.
MessageShorter.write(channelId: string, { files, ...body }: MessageCreateBodyRequest): Promise<MessageStructure>
write
(
ctx: CommandContext<{}, never>
ctx
.
CommandContext<{}, never>.channelId: string
channelId
, {
content?: string | undefined

The message contents (up to 2000 characters)

content
: 'Hello world 👋' });
}
}

Sending Embeds

Discord adds the ability to send embedded messages within a channel.

To send these embedded messages with Seyfert, we need to construct the embed using the Embed builder. For more information about customizing the embedded message, you can check out the Embed builder within this documentation.

Here’s an example of how to send an embed with a custom title and description.

src/commands/helloworld.ts
import {
class Embed

Represents a message embed.

@example const embed = new Embed(); embed.setTitle('Seyfert'); embed.setDescription('Better than discord.js'); embed.setColor('Green'); const embedJSON = embed.json();

Embed
,
class Command
Command
, type
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
} from 'seyfert';
export default class
class HelloWorldCommand
HelloWorldCommand
extends
class Command
Command
{
async
HelloWorldCommand.run(ctx: CommandContext): Promise<void>
run
(
ctx: CommandContext<{}, never>
ctx
:
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
) {
const
const embed: Embed
embed
= new
new Embed(data?: Partial<APIEmbed>): Embed

Creates a new instance of Embed.

@paramdata - The initial data for the embed.

@example const embed = new Embed({ title: 'Hello', description: 'This is an example embed' });

Embed
()
.
Embed.setTitle(title?: string): Embed

Sets the title of the embed.

@paramtitle - The title of the embed.

@returnsThe updated Embed instance.

@example embed.setTitle('This is the title');

setTitle
('My Amazing Embed')
.
Embed.setDescription(desc?: string): Embed

Sets the description of the embed.

@paramdesc - The description of the embed.

@returnsThe updated Embed instance.

@example embed.setDescription('This is the description of the embed');

setDescription
('Hello world 👋');
await
ctx: CommandContext<{}, never>
ctx
.
CommandContext<{}, never>.write<false>(body: InteractionCreateBodyRequest, withResponse?: false | undefined): Promise<void | WebhookMessage>
write
({
ResolverProps.embeds?: Embed[] | APIEmbed[] | undefined
embeds
: [
const embed: Embed
embed
] });
}
}

Sending Components Attached to the Message

Discord includes the ability to send components attached to a message within an ActionRow. These components can be Buttons or SelectMenus.

Components are stored in an ActionRow, which can contain up to 5 different buttons and only one select menu and cannot contain another ActionRow inside.

In this example, we are going to send two action rows within the message. Each row will have a button and a string select menu attached, respectively.

src/commands/helloworld.ts
import {
class ActionRow<T extends BuilderComponents>

Represents an Action Row component in a message.

ActionRow
,
class Button

Represents a button component.

Button
,
class StringSelectMenu

Represents a Select Menu for selecting string options.

@example const stringSelectMenu = new StringSelectMenu(); stringSelectMenu.setCustomId("string-select"); stringSelectMenu.addOption(new StringSelectOption().setLabel("Option 1").setValue("option_1")); stringSelectMenu.setOptions([ { label: "Option 2", value: "option_2" }, { label: "Option 3", value: "option_3" }, ]);

StringSelectMenu
,
class StringSelectOption

Represents an individual option for a string select menu.

@example const option = new StringSelectOption().setLabel("Option 1").setValue("option_1");

StringSelectOption
,
class Command
Command
,
type
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
} from 'seyfert';
export default class
class HelloWorldCommand
HelloWorldCommand
extends
class Command
Command
{
async
HelloWorldCommand.run(ctx: CommandContext): Promise<void>
run
(
ctx: CommandContext<{}, never>
ctx
:
class CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
interface CommandContext<T extends OptionsRecord = {}, M extends keyof RegisteredMiddlewares = never>
CommandContext
) {
const
const button: Button
button
= new
new Button(data?: Partial<APIButtonComponent>): Button

Creates a new Button instance.

@paramdata - The initial data for the button.

Button
()
.
Button.setCustomId(id: string): Button

Sets the custom ID for the button.

@paramid - The custom ID to set.

@returnsThe modified Button instance.

setCustomId
('helloworld')
.
Button.setLabel(label: string): Button

Sets the label for the button.

@paramlabel - The label to set.

@returnsThe modified Button instance.

setLabel
('Hello World')
.
Button.setStyle(style: ButtonStyle): Button
setStyle
(ButtonStyle.
function (enum member) ButtonStyle.Primary = 1
Primary
);
const
const buttonRow: ActionRow<Button>
buttonRow
= new
new ActionRow<Button>({ components, ...data }?: Partial<APIActionRowComponent<APIActionRowComponentTypes>>): ActionRow<...>

Creates a new instance of the ActionRow class.

@paramdata - Optional data to initialize the Action Row.

@example const actionRow = new ActionRow({ components: [buttonRawJSON] });

ActionRow
<
class Button

Represents a button component.

Button
>().
ActionRow<Button>.addComponents(...component: RestOrArray<ButtonLink | ButtonID>): ActionRow<Button>

Adds one or more components to the Action Row.

@paramcomponent - The component(s) to add.

@returnsThe updated Action Row instance.

@example actionRow.addComponents(buttonComponent); actionRow.addComponents(buttonComponent1, buttonComponent2); actionRow.addComponents([buttonComponent1, buttonComponent2]);

addComponents
(
const button: Button
button
);
const
const menu: StringSelectMenu
menu
= new
new StringSelectMenu(data?: Partial<APIStringSelectComponent>): StringSelectMenu

Represents a Select Menu for selecting string options.

@example const stringSelectMenu = new StringSelectMenu(); stringSelectMenu.setCustomId("string-select"); stringSelectMenu.addOption(new StringSelectOption().setLabel("Option 1").setValue("option_1")); stringSelectMenu.setOptions([ { label: "Option 2", value: "option_2" }, { label: "Option 3", value: "option_3" }, ]);

StringSelectMenu
()
.
SelectMenu<APISelectMenuComponent, ComponentInteraction<boolean, APIMessageComponentInteraction>>.setCustomId(id: string): StringSelectMenu

Sets the custom ID for the select menu.

@paramid - The custom ID for the select menu.

@returnsThe current SelectMenu instance.

setCustomId
('select-helloworld')
.
StringSelectMenu.addOption(...options: RestOrArray<StringSelectOption>): StringSelectMenu

Adds options to the string select menu.

@paramoptions - Options to be added.

@returnsThe current StringSelectMenu instance.

addOption
(
new
new StringSelectOption(data?: Partial<APISelectMenuOption>): StringSelectOption

Represents an individual option for a string select menu.

@example const option = new StringSelectOption().setLabel("Option 1").setValue("option_1");

StringSelectOption
().
StringSelectOption.setLabel(label: string): StringSelectOption

Sets the label for the option. label - The label for the option.

@returnsThe current StringSelectOption instance.

setLabel
('Hello').
StringSelectOption.setValue(value: string): StringSelectOption

Sets the value for the option. value - The value for the option.

@returnsThe current StringSelectOption instance.

setValue
('option_1')
);
const
const menuRow: ActionRow<StringSelectMenu>
menuRow
= new
new ActionRow<StringSelectMenu>({ components, ...data }?: Partial<APIActionRowComponent<APIActionRowComponentTypes>>): ActionRow<...>

Creates a new instance of the ActionRow class.

@paramdata - Optional data to initialize the Action Row.

@example const actionRow = new ActionRow({ components: [buttonRawJSON] });

ActionRow
<
class StringSelectMenu

Represents a Select Menu for selecting string options.

@example const stringSelectMenu = new StringSelectMenu(); stringSelectMenu.setCustomId("string-select"); stringSelectMenu.addOption(new StringSelectOption().setLabel("Option 1").setValue("option_1")); stringSelectMenu.setOptions([ { label: "Option 2", value: "option_2" }, { label: "Option 3", value: "option_3" }, ]);

StringSelectMenu
>().
ActionRow<StringSelectMenu>.addComponents(...component: RestOrArray<StringSelectMenu>): ActionRow<StringSelectMenu>

Adds one or more components to the Action Row.

@paramcomponent - The component(s) to add.

@returnsThe updated Action Row instance.

@example actionRow.addComponents(buttonComponent); actionRow.addComponents(buttonComponent1, buttonComponent2); actionRow.addComponents([buttonComponent1, buttonComponent2]);

addComponents
(
const menu: StringSelectMenu
menu
);
await
ctx: CommandContext<{}, never>
ctx
.
CommandContext<{}, never>.write<false>(body: InteractionCreateBodyRequest, withResponse?: false | undefined): Promise<void | WebhookMessage>
write
({
content?: string | undefined

The message contents (up to 2000 characters)

content
: 'Hello world 👋',
ResolverProps.components?: APIActionRowComponent<APIMessageActionRowComponent>[] | ActionRow<BuilderComponents>[] | undefined
components
: [
const buttonRow: ActionRow<Button>
buttonRow
,
const menuRow: ActionRow<StringSelectMenu>
menuRow
] });
}
}