Skip to content

Latest commit

 

History

28 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ModMail

A self-hosted Discord ModMail bot that lets your members DM the bot to open a private support ticket with your staff team, built with discord.js v14 and local SQLite storage.

Node discord.js SQLite License GitHub stars

⭐ If this project is useful to you, please consider starring the repo! It helps other server owners find it and motivates future updates.

Contents

Features

  • DM ↔ thread relay: a user's DM opens a private thread for staff, and every message flows both ways in real time.
  • Confirmation flow: the first DM from a user asks for a Yes/No confirmation before a ticket is created, to avoid accidental or spam tickets.
  • Live edit sync: if a user or a staff member edits a message they sent, the relayed copy on the other side is edited too, so both sides always see the same conversation.
  • Ticket panels: /config-ticket lets an admin drop a public button in any channel that opens a modal (reason) and creates a ticket, fully configurable (title, description, DM message, closed-DM message).
  • Typing indicators: typing in DM shows up as typing in the thread, and vice versa.
  • Delivery reactions: every relayed message gets a ✅ or ❌ reaction depending on whether delivery succeeded.
  • Block / unblock: staff can block a user from opening new tickets, right from buttons on the ticket control panel or with /block and /unblock.
  • Anti-spam auto-ignore: a user who keeps DMing without answering the confirmation prompt gets automatically ignored, with an optional log channel.
  • Components V2 control panel: a rich control panel is posted in every thread (Close / Block / Unblock buttons).
  • SQLite persistence: tickets, panels, blocklist and message mappings survive restarts; upgrading the bot never touches or drops existing data (new tables are additive only).
  • Legacy JSON import: if you're migrating from an older JSON-based version, it's imported automatically the first time the SQLite database is empty.

Getting started

Prerequisites

Install

git clone https://github.com/Cut0x/ModMail.git
cd ModMail
npm install

Configure

cp .env.example .env

Fill in .env (see Configuration below), then run:

npm start

Use npm run dev during development: it restarts automatically on file changes (node --watch).

Configuration

Required

Variable Description
DISCORD_TOKEN Your bot's token
MODMAIL_GUILD_ID The server (guild) ID the bot operates in
MODMAIL_THREADS_CHANNEL_ID A regular text channel (GuildText) where ticket threads are created

Optional

Variable Description Default
STAFF_ROLE_ID Role mentioned when a new ticket opens; also used to detect staff members (none)
BOT_ACTIVITY_PLAYING Sets the bot's status to "Playing …" (none)
THREAD_AUTO_ARCHIVE_MINUTES 60, 1440, 4320 or 10080 1440
MODMAIL_SQLITE_FILE Path to the SQLite database file ./data/modmail.sqlite
MODMAIL_DB_FILE Legacy JSON file, imported automatically once if the SQLite DB is empty ./data/modmail.json
LOGS_IGNORED_MP_USER_CHANNEL Channel where auto-ignored DM spammers are logged (none)
REACTION_SUCCESS_EMOJI Reaction added when a message is relayed successfully (unicode or <:name:id>) ✅
REACTION_FAILURE_EMOJI Reaction added when relaying fails ❌

Bot permissions & intents

Enable in the Developer Portal → Bot:

  • Message Content Intent
  • Server Members Intent (required to detect when a member leaves the server while their ticket is open)

Recommended permissions when inviting the bot:

  • View Channels
  • Send Messages / Send Messages in Threads
  • Create Private Threads
  • Manage Threads
  • Read Message History
  • Attach Files
  • Use External Emojis (optional, for custom reaction emojis)

Commands

Staff (used inside a ModMail thread)

Command Description
/close [reason] Closes the ticket and notifies the user
/block [reason] Blocks the user from opening new tickets
/unblock Unblocks the user
/help Lists available commands

Admin

Command Description
/config-ticket channel:#channel Configures and sends a public ticket-opening panel (requires Administrator)

Project structure

src/
├── config.js        # Environment variables & validation
├── index.js          # Entry point, wires everything and logs in
├── db/                # SQLite persistence layer (tickets, panels, blocklist, relayed messages)
└── bot/
    ├── client.js       # Discord client instance
    ├── ui/             # Embeds, modals, buttons, slash command builders
    ├── tickets/        # Thread lifecycle (create, close)
    ├── handlers/       # DM / staff message relay + edit sync
    ├── commands/       # Slash command & modal logic
    ├── interactions/   # Button / modal routing
    └── events/         # Discord event listeners

The codebase is kept intentionally split into small, single-purpose files (each well under 150 lines), so it's easy to navigate, review and extend: a good starting point if you want to add your own feature.

Ideas & roadmap

Nothing here is planned or promised, these are just ideas for anyone who wants to open a PR:

  • 🗑️ Delete sync: mirror message deletions the same way edits are now mirrored.
  • 📄 Ticket transcripts: export a closed ticket's conversation as HTML/Markdown when it closes.
  • 🏷️ Tags / categories: let staff label tickets (billing, bug report, etc.) for easier triage.
  • 💬 Canned responses: a /reply <snippet> command for frequently used answers.
  • 🌍 i18n: translate bot-facing strings beyond the current English/French mix.
  • ⏱️ SLA reminders: ping staff if a ticket has gone unanswered for too long.
  • 🕵️ Anonymous staff replies: an option to sign replies as "Staff" instead of a display name.
  • 🐳 Docker support: a Dockerfile + docker-compose.yml for easier self-hosting.
  • ✅ Automated tests: unit tests for the db/ layer and handler logic.
  • 📊 Basic stats/dashboard: ticket volume, response time, per-staff activity.

Have another idea? Open an issue to discuss it before starting a big PR.

Contributing

Contributions are welcome!

  1. Fork the repo and create a branch from main.
  2. Keep changes focused and files small/single-purpose, matching the existing structure.
  3. Test your changes locally (npm start against a test server) before opening a PR.
  4. Open a PR describing what changed and why.

If you run into a bug or have a feature request, please open an issue.

License

ISC (see package.json).


If this project saved you time, a ⭐ on the repo goes a long way. Thanks for checking it out!

About

A self-hosted Discord ModMail bot that lets your members DM the bot to open a private support ticket with your staff team, built with discord.js v14 and local SQLite storage.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages