1 parent
648556f762
commit
99ee3385ac
69 files changed
+1423
-1365
No files matched your search
@@ -1,59 +1,58 @@
|
||||
# RustBox 0.2.25
|
||||
# RustBox 0.2.26
|
||||
|
||||
RustBox is a webmail derived from `c0h1b4/oxi`. The consumed Oxi revision is recorded in `UPSTREAM_BASE`.
|
||||
**Fast, self-hosted webmail written in Rust.** RustBox connects to any IMAP/SMTP server and ships as one executable with the whole interface built in, so there is no Node.js, PHP or separate frontend to deploy.
|
||||
|
||||
The repository is one Cargo application. The RustBox browser interface lives under `src/web/`, uses HTML/CSS/vanilla JavaScript, and is embedded into the Rust executable at build time. There is no TypeScript, React, Next.js, Node.js or Bun build step.
|
||||

|
||||
|
||||
## Layout
|
||||
## Highlights
|
||||
|
||||
```text
|
||||
rustbox/
|
||||
├── Cargo.toml
|
||||
├── build.rs
|
||||
├── src/
|
||||
│ ├── main.rs
|
||||
│ ├── ui.rs
|
||||
│ └── web/
|
||||
│ ├── index.html
|
||||
│ ├── js/
|
||||
│ │ ├── manifest.txt
|
||||
│ │ └── *.js
|
||||
│ ├── icons.svg
|
||||
│ └── css/
|
||||
├── migrations/
|
||||
├── tests/
|
||||
├── examples/
|
||||
├── docs/
|
||||
├── packaging/
|
||||
├── scripts/
|
||||
├── config.dev.toml
|
||||
├── config.example.toml
|
||||
├── UPSTREAM_BASE
|
||||
└── dev.sh
|
||||
- Three-pane mail client with folder tree, threads, bulk actions, drag and drop, snooze, undo send and undo move.
|
||||
- HTML, plain-text and Markdown composer with inline images, drafts, identities, signatures and OpenPGP.
|
||||
- Server-side filters (Sieve) with a visual editor, exceptions, templates and **Apply now** for mail that is already in a folder.
|
||||
- Calendar with reminders and ICS import/export, contacts with groups and vCard.
|
||||
- Realtime new-mail updates and desktop notifications.
|
||||
- 43 interface styles, from Gmail- and Outlook-inspired to Dracula and Windows XP, plus a fully adjustable custom style, light/dark/time-of-day themes and a mobile layout.
|
||||
- SQLite, MySQL or PostgreSQL; local disk, shared filesystem or S3 storage; built-in search or OpenSearch; optional cluster mode.
|
||||
- English and Polish interface.
|
||||
|
||||
The complete list, with screenshots, is in **[docs/FEATURES.md](docs/FEATURES.md)**.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
|  |  |
|
||||
|  |  |
|
||||
|
||||
## Quick start
|
||||
|
||||
```bash
|
||||
# development server with config.dev.toml
|
||||
./dev.sh
|
||||
# then open http://127.0.0.1:3001
|
||||
```
|
||||
|
||||
`build.rs` combines the CSS modules from `src/web/css/manifest.txt` and JavaScript modules from `src/web/js/manifest.txt`. Cargo embeds the generated CSS/JS bundles, HTML and SVG sprite in the RustBox executable. There is no standalone source `src/web/app.js`; `src/web/` is the single source of truth and Cargo generates the embedded bundles in `OUT_DIR`.
|
||||
Production build and systemd installation:
|
||||
|
||||
## Storage and search in 0.2.16
|
||||
```bash
|
||||
./scripts/build-release.sh
|
||||
sudo ./scripts/install-systemd.sh
|
||||
sudo systemctl enable --now rustbox
|
||||
```
|
||||
|
||||
RustBox separates three concerns: SQL metadata, blob storage and search. The SQL engine does **not** decide whether `data_dir` may be used. A single-node PostgreSQL/MySQL deployment may still use filesystem blobs and local Tantivy. In cluster mode, local node state is rejected unless the configured backend is explicitly shared.
|
||||
Docker Compose examples (SQLite; PostgreSQL + S3 + OpenSearch; MySQL + NFS + OpenSearch; HA with Garage) are in [`docker/`](docker/README.md).
|
||||
|
||||
Blob backends:
|
||||
## Documentation
|
||||
|
||||
- `storage.backend="filesystem"` — local disk in single-node mode; set `storage.shared=true` only for a real shared POSIX mount such as NFS, CephFS or GlusterFS.
|
||||
- `storage.backend="s3"` — AWS S3 or compatible APIs such as MinIO/Ceph RGW.
|
||||
|
||||
Physical blob deletion is durable across all blob backends. RustBox records deletion work in the per-account SQL `blob_delete_outbox` in the same transaction that removes attachment metadata, attempts the delete immediately, and retries temporary failures in the background with leases/backoff. This covers local disk, shared POSIX/NFS and S3-compatible storage without permanently dead-lettering failed cleanup.
|
||||
|
||||
Search backends:
|
||||
|
||||
- `search.backend="local_tantivy"` — single-node.
|
||||
- `search.backend="opensearch"` — cluster-capable. Index mutations are written first to a durable per-tenant SQL outbox and processed with retry/backoff/dead-letter handling.
|
||||
- `search.backend="disabled"` — no full-text index.
|
||||
|
||||
In a cluster using shared SQL + S3/shared POSIX + OpenSearch/disabled search + `pgp_enabled=false`, `data_dir` is not required as persistent node state. See `docker/README.md` for ready Compose variants.
|
||||
|
||||
Administrator-only deep runtime diagnostics can be enabled separately under `[diagnostics_endpoint]`. It is disabled and loopback-only by default, supports a network allowlist plus token or Basic Auth, redacts secrets, and probes SQL/Redis/storage/search/session/runtime/security state. See [`docs/SYSTEM_DIAGNOSTICS.md`](docs/SYSTEM_DIAGNOSTICS.md).
|
||||
| Document | Contents |
|
||||
|---|---|
|
||||
| [Features](docs/FEATURES.md) | Everything RustBox does, with screenshots |
|
||||
| [Storage and search](docs/STORAGE_SEARCH_OPERATIONS.md) | Backends, shared storage, migrations, failure modes |
|
||||
| [System diagnostics](docs/SYSTEM_DIAGNOSTICS.md) | Administrator diagnostics endpoint |
|
||||
| [IMAP connection pool](docs/imap-pool.md) | How IMAP sessions are reused |
|
||||
| [Docker](docker/README.md) | Compose deployments |
|
||||
| [Releasing](docs/RELEASING.md) · [Validation](docs/VALIDATION.md) | Release process and checks |
|
||||
| [Implementation status](docs/IMPLEMENTATION_STATUS.md) | Detailed technical status |
|
||||
| [Changelog](CHANGELOG.md) | Changes per version |
|
||||
| [Database migrations](migrations/README.md) | Schema baseline and upgrades |
|
||||
|
||||
## Configure mail servers
|
||||
|
||||
@@ -117,6 +116,27 @@ Mail-size limits are intentionally separate. `max_attachment_size_mb` applies to
|
||||
|
||||
Attachments are streamed to blob storage on upload, but sending a message or saving an IMAP draft snapshot has to hold them in memory while the MIME message is built. RustBox therefore (1) rejects an attachment set whose base64-encoded size cannot fit `max_message_size_mb` with `413` before any file is read into memory, and also while an upload is still streaming, and (2) allows only `max_concurrent_message_builds` such operations at the same time; further requests wait up to `message_build_wait_secs` and then receive `503`. Peak RAM for these operations is roughly `max_concurrent_message_builds` x 4 x `max_message_size_mb`. Fully streamed MIME assembly is not implemented.
|
||||
|
||||
## Storage and search
|
||||
|
||||
RustBox separates three concerns: SQL metadata, blob storage and search. The SQL engine does **not** decide whether `data_dir` may be used. A single-node PostgreSQL/MySQL deployment may still use filesystem blobs and local Tantivy. In cluster mode, local node state is rejected unless the configured backend is explicitly shared.
|
||||
|
||||
Blob backends:
|
||||
|
||||
- `storage.backend="filesystem"` — local disk in single-node mode; set `storage.shared=true` only for a real shared POSIX mount such as NFS, CephFS or GlusterFS.
|
||||
- `storage.backend="s3"` — AWS S3 or compatible APIs such as MinIO/Ceph RGW.
|
||||
|
||||
Physical blob deletion is durable across all blob backends. RustBox records deletion work in the per-account SQL `blob_delete_outbox` in the same transaction that removes attachment metadata, attempts the delete immediately, and retries temporary failures in the background with leases/backoff. This covers local disk, shared POSIX/NFS and S3-compatible storage without permanently dead-lettering failed cleanup.
|
||||
|
||||
Search backends:
|
||||
|
||||
- `search.backend="local_tantivy"` — single-node.
|
||||
- `search.backend="opensearch"` — cluster-capable. Index mutations are written first to a durable per-tenant SQL outbox and processed with retry/backoff/dead-letter handling.
|
||||
- `search.backend="disabled"` — no full-text index.
|
||||
|
||||
In a cluster using shared SQL + S3/shared POSIX + OpenSearch/disabled search + `pgp_enabled=false`, `data_dir` is not required as persistent node state. See `docker/README.md` for ready Compose variants.
|
||||
|
||||
Administrator-only deep runtime diagnostics can be enabled separately under `[diagnostics_endpoint]`. It is disabled and loopback-only by default, supports a network allowlist plus token or Basic Auth, redacts secrets, and probes SQL/Redis/storage/search/session/runtime/security state. See [`docs/SYSTEM_DIAGNOSTICS.md`](docs/SYSTEM_DIAGNOSTICS.md).
|
||||
|
||||
## Database, storage, search and cluster traffic
|
||||
|
||||
`database_backend = "sqlite" | "mysql" | "pgsql"` selects only the authoritative SQL database. It does not force or forbid local blob/search storage. In particular, PostgreSQL/MySQL are valid in a single-node installation together with `storage.backend="filesystem"` and `search.backend="local_tantivy"`.
|
||||
@@ -183,8 +203,28 @@ rustbox search reindex
|
||||
|
||||
Ready Docker examples are in `docker/`: standalone SQLite, PostgreSQL + SILO (S3-compatible) + OpenSearch, and MySQL + NFS + OpenSearch.
|
||||
|
||||
All executable application SQL is centralized by dialect under `src/queries/{sqlite,mysql,pgsql}/queries.rs`. Migrations V047-V052 are consolidated into the V052 compatibility baseline; databases older than V052 must first be upgraded with a release that can reach that baseline (0.2.22). RustBox 0.2.23 adds V053 for the appearance `skin_depth` and `skin_gradients` settings and 0.2.24 adds V054 for the time-of-day theme and per-account colour; fresh schemas already contain the columns, while existing tenants migrate automatically. V055 is the next migration number. See `migrations/README.md`.
|
||||
Database schema upgrades run automatically at startup. Databases older than the consolidated baseline (V052) must first be opened once with RustBox 0.2.22. See `migrations/README.md` for the schema history; V055 is the next migration number.
|
||||
|
||||
## ManageSieve
|
||||
|
||||
Supported modes:
|
||||
|
||||
- `starttls` — recommended;
|
||||
- `implicit` — TLS immediately after connect;
|
||||
- `none` — plaintext transport; reusable credential authentication remains blocked unless `sieve_allow_insecure_auth = true` is explicitly enabled.
|
||||
|
||||
When `sieve_host` is not configured, RustBox uses the authenticated session's IMAP host. Sieve uses the same session credentials; passwords are not exposed to the browser after login.
|
||||
|
||||
## Native installation
|
||||
|
||||
```bash
|
||||
./scripts/build-release.sh
|
||||
sudo ./scripts/install-systemd.sh
|
||||
sudo systemctl enable --now rustbox
|
||||
sudo journalctl -u rustbox -f
|
||||
```
|
||||
|
||||
For public access put an HTTPS reverse proxy in front of RustBox. The production example binds to `127.0.0.1:3001`.
|
||||
|
||||
## Development
|
||||
|
||||
@@ -214,72 +254,27 @@ cargo test
|
||||
cargo build --release
|
||||
```
|
||||
|
||||
## UI
|
||||
## Project layout
|
||||
|
||||
Multi-account browser sessions are enabled by default and can be disabled by the administrator with `multi_account_enabled = false`. When enabled, signed-in accounts can be switched from the top bar and selected together for new-mail notifications.
|
||||
|
||||
RustBox uses a compact three-pane mail layout: folders, message list and reader. The current internal baseline includes configurable special IMAP folders, collapsible folder hierarchy, folder CRUD/subscriptions, move/copy/bulk actions, drag-and-drop message moves, collapsible threads, raw headers/source download, labels, advanced/saved search, quota warnings, contacts/groups/vCard, calendar/ICS import, identities/signatures with automatic reply identity selection, HTML/plain/Markdown compose modes, CID inline images, and ManageSieve raw + visual rule editing with negation, dynamically addable conditions/actions and nested AND/OR chaining. OpenPGP includes per-user key management, identity binding, PGP/MIME + inline sign/encrypt/decrypt/verify, WKD/HKP discovery and private-key passphrase management.
|
||||
|
||||
IMAP IDLE events are delivered to the browser over the embedded WebSocket endpoint for realtime refresh and optional desktop notifications. Notification preferences include sound, folder selection and Do Not Disturb hours.
|
||||
|
||||
Appearance preferences are persisted per account and include light/dark/system theme, density, preview position, UI scale, multiple color presets, custom accent/background/panel/text colors, font, row height, pane widths, radius, contrast and visibility toggles. Administrators can set the global light/dark mode with `default_theme = "system" | "dark" | "light"` and the global interface style with `default_interface_skin = "rustbox" | "gmail" | "proton" | "zoho" | "outlook" | ...` in TOML. The global interface style is used on the login screen and by accounts set to **Global default**. Built-in interface styles include RustBox, Roundcube variants, Clean, Graphite, High contrast, Gmail/Proton/Zoho/Outlook/Fastmail/Apple Mail/Yahoo/HEY/GitHub/GitLab/Discord/Slack/Reddit/Notion-inspired profiles, Nord and Minimal. Predefined styles can optionally unlock the per-account UI scale control. The mailbox toolbar also exposes persisted date/sender/subject/size sorting, and remote images can be restricted to saved contacts.
|
||||
|
||||
The native RustBox interface intentionally uses flat surfaces, small radii and one SVG icon set. Compatibility skins may reproduce upstream visual treatments such as gradients, while toolbar icons remain SVG rather than Unicode glyphs.
|
||||
|
||||
## ManageSieve
|
||||
|
||||
Supported modes:
|
||||
|
||||
- `starttls` — recommended;
|
||||
- `implicit` — TLS immediately after connect;
|
||||
- `none` — plaintext transport; reusable credential authentication remains blocked unless `sieve_allow_insecure_auth = true` is explicitly enabled.
|
||||
|
||||
When `sieve_host` is not configured, RustBox uses the authenticated session's IMAP host. Sieve uses the same session credentials; passwords are not exposed to the browser after login.
|
||||
|
||||
## Native installation
|
||||
|
||||
```bash
|
||||
./scripts/build-release.sh
|
||||
sudo ./scripts/install-systemd.sh
|
||||
sudo systemctl enable --now rustbox
|
||||
sudo journalctl -u rustbox -f
|
||||
```text
|
||||
src/ Rust application (Axum server, IMAP/SMTP, Sieve, storage, search)
|
||||
src/web/ Browser interface: index.html, css/, js/, i18n/, icons.svg
|
||||
migrations/ SQL schemas for SQLite, MySQL and PostgreSQL
|
||||
docker/ Compose examples
|
||||
packaging/ systemd unit, logrotate and production config
|
||||
scripts/ Build, install, release and Roundcube import helpers
|
||||
docs/ Documentation and screenshots
|
||||
```
|
||||
|
||||
For public access put an HTTPS reverse proxy in front of RustBox. The production example binds to `127.0.0.1:3001`.
|
||||
`build.rs` bundles the CSS and JavaScript modules listed in `src/web/css/manifest.txt` and `src/web/js/manifest.txt`; the bundles, HTML, translations and icons are embedded in the executable.
|
||||
|
||||
## Following Oxi
|
||||
## License
|
||||
|
||||
Initialize Git after extracting the release archive:
|
||||
Copyright © 2026 Mateusz Gruszczyński ([linuxiarz.pl](https://linuxiarz.pl)).
|
||||
|
||||
```bash
|
||||
git init
|
||||
git add .
|
||||
git commit -m "RustBox 0.2.16 release"
|
||||
./scripts/setup-upstream.sh
|
||||
```
|
||||
RustBox is dual-licensed:
|
||||
|
||||
Inspect newer Oxi changes:
|
||||
- **GNU Affero General Public License v3** ([`LICENSE`](LICENSE)) — free to use, modify and share, also in companies. If you run a modified version as a network service, offer its source code to its users.
|
||||
- **Commercial license** — for organisations that prefer different terms, for example to keep their changes private. Paid; terms by agreement. Contact: [linuxiarz@linuxiarz.pl](mailto:linuxiarz@linuxiarz.pl). Contacting the author is voluntary and never required for use that follows the AGPL.
|
||||
|
||||
```bash
|
||||
./scripts/oxi-status.sh
|
||||
```
|
||||
|
||||
Import the mapped Oxi backend delta:
|
||||
|
||||
```bash
|
||||
./scripts/sync-upstream.sh
|
||||
```
|
||||
|
||||
Oxi `backend/...` paths are mapped into RustBox's flat Cargo tree. Oxi frontend sources are never copied. Relevant upstream frontend behavior is reviewed and reimplemented in `src/web/`. `UPSTREAM_BASE` advances only after `./scripts/finish-upstream.sh` completes review and the build gate.
|
||||
|
||||
To port one backend commit without advancing the baseline:
|
||||
|
||||
```bash
|
||||
./scripts/oxi-port-commit.sh <oxi-commit>
|
||||
```
|
||||
|
||||
See `docs/UPSTREAM.md` for details.
|
||||
|
||||
## Attribution
|
||||
|
||||
See `NOTICE.md`. The supplied Oxi snapshot did not contain an authoritative `LICENSE` file; verify the exact upstream licensing terms before public redistribution.
|
||||
Details: [`LICENSING.md`](LICENSING.md). The first version of RustBox was created as a fork of [Oxi](https://github.com/c0h1b4/oxi) (MIT License); see [`NOTICE.md`](NOTICE.md).
|
||||
Reference in new issue
Block a user