Commit Graph
172 Commits
Author SHA1 Message Date
Hieu Nguyen (Jack) 73d8ebfe16 Merge pull request #55 from hieunc229/pr-52
Pr 52
2026-09-28 16:23:52 +07:00
Hieu Nguyen (Jack) 8c224a88eb run check with gpt, pump version 2026-09-28 16:17:54 +07:00
Hieu Nguyen (Jack) 92134bbf35 Merge pull request #48 from egamer24/fix/mobile-layout
Fix mobile layout
2026-09-28 15:30:21 +07:00
Hieu Nguyen (Jack) da6321712e Merge current main into mobile layout PR 2026-09-28 15:29:31 +07:00
Hieu Nguyen (Jack) 76711e9682 Improve message original view 2026-09-28 15:25:20 +07:00
Hieu Nguyen (Jack) 1ae2412fcb improve email attachments 2026-09-28 14:54:46 +07:00
Hieu Nguyen (Jack) 7e4c109c7c ran security audit 2026-09-28 14:20:24 +07:00
James 26923a4cb9 Migrate Cloudflare runtime from OpenNext to vinext 2026-09-27 20:29:09 +01:00
Hieu Nguyen (Jack) 20a941bba6 improve jmap 2026-09-28 01:30:10 +07:00
Hieu Nguyen (Jack) 6093247237 update menu icon 2026-09-28 01:05:38 +07:00
Hieu Nguyen (Jack) 973e2d9efe add proper calendar 2026-09-28 01:02:37 +07:00
Hieu Nguyen (Jack) f4e3c31512 add browser notification 2026-09-27 18:59:33 +07:00
Hieu Nguyen (Jack) 55c0048941 [assistant] added message queue 2026-09-27 18:45:09 +07:00
Hieu Nguyen (Jack) 9a4841a8a3 make email header stick 2026-09-27 17:48:16 +07:00
Hieu Nguyen (Jack) b4ab412f7d improve agent 2026-09-27 17:27:17 +07:00
Hieu Nguyen (Jack) 13170d2b0e update readme 2026-09-27 15:40:34 +07:00
Hieu Nguyen (Jack) ec54476edd Update package-lock.json 2026-09-27 15:29:57 +07:00
Hieu Nguyen (Jack) d34ed172a9 pump version 2026-09-27 15:26:45 +07:00
Hieu Nguyen (Jack) b2ca083b85 Update README.md 2026-09-27 15:25:28 +07:00
Hieu Nguyen (Jack) 403c649d96 persist menu width between pages 2026-09-27 15:24:21 +07:00
Hieu Nguyen (Jack) 2ef02b8f72 update agent scope 2026-09-27 15:20:32 +07:00
Hieu Nguyen (Jack) f9ae5a46a8 fix backup missing tables 2026-09-27 14:16:11 +07:00
Hieu Nguyen (Jack) f1e2aeec1b improve ui 2026-09-27 14:14:31 +07:00
Hieu Nguyen (Jack) da9b803bdb added MCP / Agent 2026-09-27 13:57:31 +07:00
egamer24andClaude Opus 5.5 e4d765132d Fix mobile layout: icon-rail sidebar and narrow-screen wrapping
Below md the sidebar collapses to a 72px icon rail and expands as an
overlay that closes on navigation; the resize handle is hidden there.
The message list uses the compact row layout on phones, the message
toolbar, sender header and thread headers wrap, and the settings nav
stacks above the form.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 15:11:14 -07:00
Hieu Nguyen (Jack) eca1e143bf improve compose form 2026-09-24 17:51:52 +07:00
Hieu Nguyen (Jack) 3896f2e506 make columns resizable 2026-09-24 17:51:45 +07:00
Hieu Nguyen (Jack) be6459da5e add email original view 2026-09-24 16:21:52 +07:00
Hieu Nguyen (Jack) 29c47be7c6 improve render email content 2026-09-24 15:27:07 +07:00
Hieu Nguyen (Jack) b0d70ab484 improve avatar 2026-09-24 15:19:50 +07:00
Hieu Nguyen (Jack) 981326cc89 add rules to prevent bots / crawlers 2026-09-24 14:47:46 +07:00
Hieu Nguyen (Jack) 266c75314c Update .gitignore 2026-09-24 14:47:24 +07:00
Hieu Nguyen (Jack) 1bf70d2ef2 Update screenshot / sponsors 2026-09-20 13:45:32 +07:00
Hieu Nguyen (Jack) 833ed824ae improve domain card 2026-09-20 13:33:41 +07:00
Hieu Nguyen (Jack) c1f4c24525 improve domain card 2026-09-20 09:24:31 +07:00
Hieu Nguyen (Jack) 214fb2a54f improve domain setup / record checking 2026-09-20 08:58:43 +07:00
Hieu Nguyen (Jack) 15697a796b improve auto-update workflow 2026-09-18 23:22:19 +07:00
Hieu Nguyen (Jack) d5b8c413ba improve ui 2026-09-18 17:58:55 +07:00
Hieu Nguyen (Jack) dd67f90cf3 improve setup 2026-09-18 16:47:03 +07:00
Hieu Nguyen (Jack) 76adbc8ebd [setup] delete MX if already exist 2026-09-18 15:58:50 +07:00
Hieu Nguyen (Jack) c5c756a775 update migration flow 2026-09-18 15:28:13 +07:00
c1441cedd5 feat(jmap): Email/import for MIME-composing clients, and the header query filter (#46)
* fix(jmap): answer the header filter in Email/query instead of ignoring it

conditionToSql() had no `header` branch, so a condition it did not
recognise was dropped and the query matched every message in the
mailbox. A client that de-duplicates drafts by Message-ID before
importing therefore either adopted an unrelated draft or refused to
send because "multiple remote drafts" came back.

Handle `header` per RFC 8621 §4.4.1 from the columns Mailflare already
stores — Message-ID, In-Reply-To and References — and make every other
header name an `unsupportedFilter` error, which is what RFC 8620 §5.5
requires of a filter the server cannot apply. Message-IDs compare
without angle brackets, since inbound rows store them and outbound rows
do not, and header names are matched case-insensitively.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat(jmap): Email/import so MIME-composing clients can send

Clients that build MIME locally — Flectar Mail and anything else on the
jmap-client crate — send by uploading the raw message, importing it into
Drafts and submitting it. Email/import answered `unknownMethod`, so
reading worked but every send failed.

Implement it for the Drafts mailbox (RFC 8621 §4.8). The blob must be an
upload this account owns, the target exactly one Drafts mailbox, and the
parsed From has to pass the same getAuthorizedSenderAddress() check a
draft created through Email/set does; anything else comes back in
notCreated as blobNotFound, invalidProperties, invalidEmail, forbidden
or tooLarge. Importing into arbitrary mailboxes is deliberately left
out: delivered mail belongs to the inbound pipeline, which owns
threading, spam scoring and inbound state.

The parsed headers fill the same columns Email/set create writes —
Email/set create and Email/import now share one insert and one target
rule — plus providerMessageId, which is what lets the client find its
own draft again with a Message-ID filter. The uploaded bytes are kept
verbatim under `drafts/<messageId>.eml`, so downloading the message's
blob returns the client's own MIME instead of the rebuilt minimal
message, and the jmap-uploads object is released once claimed.

Email/copy and Email/parse stay unsupported.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(jmap): cover Email/import validation and the header filter

tests/jmap-email-import.test.mjs is a node:test file over the pure
pieces — the mailbox rule, keyword and receivedAt parsing, and the SQL
Email/query builds for header conditions, including the unsupportedFilter
throw and the regression that a Message-ID filter narrows the mailbox
instead of matching every draft. The modules are TypeScript behind the
`@/*` alias, so they are bundled with the esbuild the repo already uses
for the self-hosted server rather than loaded directly; nothing here
needs a Workers binding.

scripts/jmap-import-check.mjs is the end-to-end pass against
`npm run dev`: upload a multipart message with an attachment, import it,
read it back, download the blob byte-for-byte, query it by Message-ID,
submit it, and check every rejection path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(jmap): document Email/import and the header query filter

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(jmap): clean up imported draft objects

---------

Co-authored-by: egamer24 <25360766+egamer24@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Hieu Nguyen (Jack) <nc.hieu@live.com>
2026-09-18 15:16:52 +07:00
rome-xi 4a6328557f fix(domains): skip Worker catch-all on Node/Docker runtime (#42) (#44)
Self-hosted Node/Docker has no Email Worker named mailflare, so the
catch-all PUT 404s (Cloudflare code 2016) during domain setup even when
CF_TOKEN can edit zone routing. Gate ensureEmailRoutingCatchAllToWorker
with isNodeRuntime; Workers still bind catch-all as before.
2026-09-18 15:08:29 +07:00
Hieu Nguyen (Jack) 554744c566 Merge pull request #38 from Docker-Hunterpedia/feat/self-host-docker
feat(self-host): run Mailflare as a Docker container on any host
2026-09-13 13:24:32 +07:00
Oday BakkourandClaude Fable 5.1 f0dc5a16fc feat(self-host): run Mailflare as a Docker container on any host
Adds a second runtime next to Cloudflare Workers. One Node process serves
the Next app, a realtime WebSocket hub, the job queues, the backup schedule
and an SMTP listener; SQLite and local files replace D1 and R2. The
application code is unchanged: the runtime builds an object with the same
binding interfaces (`server/runtime/`) and publishes it before Next starts,
so `getEnv()` hands route handlers the same shape on both platforms.

Runtime (server/)
- `sqlite-database.ts`: the D1 API over better-sqlite3, so Drizzle's D1
  driver, the raw `env.DB.prepare` callers, the FTS5 index and its triggers
  all work as-is. Migrations are applied from drizzle/migrations at start,
  recorded in `d1_migrations` like Wrangler does.
- `file-bucket.ts`: the R2 API over a directory, with metadata sidecars and
  byte ranges. `mailer.ts`: the send_email builder over nodemailer (any SMTP
  relay) or Cloudflare's Email Sending REST API; generates the Message-ID so
  threading matches Workers. `queue.ts`: in-process queues with the same
  retry policy. `realtime.ts`: per-user WebSocket fan-out in place of the
  Durable Object. `misc.ts`: rate limiter and ASSETS fetcher.
- `smtp.ts`: inbound SMTP on port 25 via smtp-server; reject rules answer
  550, forward rules relay the raw message through the outbound SMTP.
- `index.ts`: the custom server; `scripts/build-server.mjs` bundles it with
  esbuild to dist/server.mjs.

Application changes
- `src/lib/runtime.ts` + `getEnv()` prefer the Node env when present.
- `src/lib/email/intake.ts` factors the Worker email handler's logic so the
  SMTP listener and the new signed `/api/inbound` webhook share it.
- Domains without Cloudflare credentials are recorded with zone id
  "manual": Cloudflare calls no-op, the domain is active at once, and the
  DNS page lists MX/SPF/DMARC records to create. Setup checks, the domains
  page copy and the self-update button adapt to the runtime; `/api/auth/me`
  exposes `runtime` and `managesDns`.
- `APP_URL` overrides the origin for reset links and the JMAP session
  behind a proxy. The direct `getCloudflareContext` import in the update
  route is replaced with `getEnv()`.

Deployment
- Dockerfile (multi-stage, 1.1 GB, Workers toolchain pruned), compose file,
  `.env.docker.example`, `docs/self-hosting.md`, README section.
- `deploy/cloudflare-email-relay`: a Worker that keeps MX on Cloudflare
  Email Routing and posts messages to the server with an HMAC signature,
  acting on the reject/forward decision it returns.

Verified on a fresh data directory and again inside the built image:
migrations apply, first-run setup and registration work with no Cloudflare
credentials, mail over SMTP lands in the inbox with the raw copy on disk,
a reject rule answers 550, a send through SMTP_URL loops back and is stored
as sent and received, an inbound reply threads with the sent copy, FTS
search finds body text, a backup completes to the volume, the WebSocket
delivers a push, the relay webhook rejects a bad signature and returns
store/reject decisions, JMAP serves a session with the APP_URL origin.
Container healthcheck reports healthy. tsc (11) and eslint (105) unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGeWDVSkXtVEmDAN2AtB9h
2026-09-12 14:34:11 +03:00
Hieu Nguyen (Jack) 706598d4a7 Merge pull request #37 from egamer24/fix/mailbox-naming
fix(mailboxes): give each personal mailbox its own name and avatar
2026-09-12 16:38:47 +07:00
Hieu Nguyen (Jack) 5787763e95 Merge remote-tracking branch 'origin/main' into pr/37
# Conflicts:
#	src/app/api/messages/route.ts
2026-09-12 16:38:43 +07:00
Hieu Nguyen (Jack) 69fef6978c Merge pull request #35 from brucemclachlan/fix/backup-mailbox-aliases
fix(backups): back up the mailbox_aliases table
2026-09-12 16:30:16 +07:00
Hieu Nguyen (Jack) da0958b2aa Merge remote-tracking branch 'origin/main' into pr/35
# Conflicts:
#	src/lib/backups/export.ts
#	src/lib/backups/types.d.ts
2026-09-12 16:30:05 +07:00
Hieu Nguyen (Jack) 412542e334 Merge pull request #34 from Docker-Hunterpedia/feat/jmap
feat(jmap): JMAP server for external mail clients
2026-09-12 16:28:55 +07:00