Oday BakkourandClaude Fable 5.1 98100ef934 feat(search): full-text search with Gmail-style operators on an FTS5 index
Search covered four columns with LIKE and never looked at message bodies.
This adds an FTS5 index over subject, sender, recipients and both bodies,
kept in sync by triggers, and a query grammar that both the search box and
the public API understand.

- Migration 0030 creates `messages_fts` as an external-content table (bodies
  are read from `messages`, not stored twice) with insert/update/delete
  triggers, and rebuilds it once so existing mail is indexed.
- `src/lib/search/query-utils.ts` parses `from:`, `to:` (covers Cc),
  `subject:`, `has:attachment`, `is:unread|read|starred`, `after:`/`before:`,
  quoted phrases and `-negation`, and builds a MATCH expression with every
  user value quoted so input cannot alter the query. Plain terms match by
  prefix. The legacy `title:` and `:unread` forms still work.
- `buildSearchConditions` turns that into a `rowid IN (SELECT rowid FROM
  messages_fts WHERE messages_fts MATCH ?)` predicate plus column filters,
  used by `/api/messages` and now `/api/v1/messages?q=`.
- The search box is debounced (250 ms) so a typed word costs one request.
- `GET`/`POST /api/admin/search-index` reports index vs table counts and
  rebuilds on demand.
- The bootstrap schema splitter now keeps trigger bodies whole, and the
  backup coverage check skips the FTS shadow tables (derived data that
  repopulates on restore). While there, `mailbox_aliases` was missing from
  BACKUP_TABLES, which made every backup fail on main; it is added.

Verified on local D1: all operators return the expected rows against the
seed data, hostile input (`x" OR "y`, `term)(`) is matched literally,
a draft edit and delete update the index immediately, rebuild is a no-op
on a consistent index, and a backup completes with the index present.
tsc (11) and eslint (105) unchanged from main.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 15:03:00 +03:00
2026-09-06 08:25:18 +07:00
2026-05-26 08:19:09 +07:00
2026-05-26 10:56:49 +07:00
2026-09-03 03:12:03 +07:00
2026-09-08 15:42:33 +07:00
2026-09-06 11:12:45 +07:00
2026-08-30 20:54:36 +07:00
2026-05-26 08:19:09 +07:00
2026-05-26 08:19:09 +07:00
2026-05-26 08:19:09 +07:00
2026-09-06 11:12:45 +07:00
2026-09-03 02:51:44 +07:00
2026-08-25 11:15:20 +07:00
2026-09-02 02:23:24 +07:00
2026-09-08 11:59:21 +07:00
2026-05-26 08:19:09 +07:00
2026-09-06 11:12:31 +07:00
2026-05-27 09:57:54 +07:00
2026-06-18 23:24:27 +07:00
2026-09-06 11:12:45 +07:00
2026-09-06 11:12:45 +07:00

Mailflare

Mailflare

Mailflare is a self-hosted email inbox for custom domains, built on Cloudflare.

Deploy to Cloudflare

Mailflare inbox

Thanks to mailflare sponsors. Want to support the project? Drop @hieuSSR a message

Sequenzy

What you can do

  • Connect domains and set up Cloudflare Email Routing from the dashboard.
  • Create personal and shared mailboxes with delegated access.
  • Send and receive email with attachments, rich formatting, signatures, and automatic replies.
  • Organize mail with search, custom folders, stars, snoozing, archive, spam, and trash.
  • Create routing rules to store, forward, reject, or categorize incoming messages.
  • Get real-time inbox updates and new-message notifications.
  • Import and export mail, manage contacts, and block unwanted senders.
  • Manage accounts, permissions, API keys, webhooks, audit logs, and database backups.

How it works

Mailflare runs in your Cloudflare account. Email Routing delivers incoming messages to the app, while Cloudflare's email service handles outgoing messages. Your mail data stays in your own D1 database and attachments are stored in your own R2 bucket.

How much does it cost?

You can setup Mailflare and receive email for free

A Paid Worker plan ($5/month) is required to send email (and it's recommend to have a smooth experience)

Deploy

Getting started takes three steps:

  1. Deploy the app. Click Deploy to Cloudflare and keep the app name as mailflare. The app will not work correctly under another Worker name.
  2. Complete setup. Open the deployed app and follow /setup to check the installation and create your admin account.
  3. Connect your domain. Add a domain managed by the same Cloudflare account. Mailflare configures its email routing and helps you create the first mailbox.

⚠️ IMPORTANT: CF_TOKEN is required during deployment. Create a scoped Cloudflare API token with the following permissions for the domains you want to connect.

  • All accounts - Email Sending:Edit, DNS Settings:Edit, Email Routing Addresses:Edit
  • All zones - DNS Settings:Edit, Email Routing Rules:Edit, Zone Settings:Edit, DNS:Edit

See the deployment guide for required permissions, manual deployment, backups, and updates.

Local development

cp .dev.vars.example .dev.vars
npm install
npm run db:migrate:local
npm run dev

Add your Cloudflare credentials to .dev.vars, then open http://localhost:3000. For sample local data, run npm run db:seed while the development server is running.

Documentation

License

See LICENSE.

S
Description
Email for professionals and teams
https://mailflare.co
Readme AGPL-3.0
70 MiB
0 Stars 1 Watchers 0 Forks
Languages
TypeScript 92.6%
JavaScript 6.7%
CSS 0.6%