chore: update version to 1.8.0

This commit is contained in:
Linus Rath
2026-08-06 19:32:26 +02:00
parent 905e6ed96f
commit b50f71fa5c
6 changed files with 99 additions and 8 deletions
+68
View File
@@ -1,5 +1,73 @@
# Changelog
## 1.8.0 (2026-08-06)
### Features
- **Mail**: Nest tags in a tree by picking a parent when you create one
- **Mail**: Per-tag visibility — always, only when unread, or always hidden
- **Mail**: Assign and clear several tags at once, with a reworked tag display
- **Mail**: Recover tags from the server by scanning mail for JMAP keywords no local tag explains (#658)
- **Mail**: "Forward as attachment" in the viewer and the message-list context menu
- **Mail**: Refresh button in the mail-list toolbar
- **Composer**: Confirm sending without a subject instead of blocking the send, with "Don't ask again" (#684)
- **Contacts**: Contact cards for organizations (#701)
- **Security**: Manage S/MIME and PGP public keys and configure Stalwart encryption at rest from account security settings
- **Notifications**: Background notification onboarding, sequenced after the PWA install prompt
- **Navigation**: Deep links for mail, calendar, contacts, files, and settings, with screen-reader improvements
- **Settings**: Always show the Unified Mailbox switch in Layout settings
- **i18n**: Catalan translation
- **i18n**: Localized editor toolbar across every locale
- **Plugins**: Contact API — `contact.get`, `contact.create`, `contact.update`, `contact.search`
- **Plugins**: `user.getAccounts` and `user.getIdentities`
- **Plugins**: `user.logout` method and logout hook
- **Plugins**: Crypto API — public-key management and encryption-at-rest control on the privileged tier
- **Plugins**: `onBeforeBlobUpload` can offload an attachment to external storage
- **Plugins**: Binary `Blob`/`File` bodies for `api.http.post`
- **Plugins**: `upfiles.get` moved behind `email:blob-read`, off the privileged tier
- **Dev**: Mock JMAP defaults now include nested tags
### Changes
- **Mail**: The "Reset to defaults" button is gone from tag settings — one stray click wiped a carefully built tag list, with no confirmation and no undo
### Fixes
- **Send**: Send through the identity's own account client so DKIM matches the From domain (#461)
- **Send**: Split `Name <addr>` recipients into the JMAP `name` and `email` fields (#672)
- **Send**: Time out stalled JMAP requests so a send can't hang forever (#702)
- **Mail**: Keep inline images when replying to `application/octet-stream` cid parts (#543)
- **Mail**: Reply on your own thread message no longer re-addresses the original recipients (#703)
- **Mail**: Empty folder no longer stops after 500 emails (#711)
- **Mail**: Move messages across accounts from the "Move to" context menu, preserving read state and deferring source removal to Stalwart
- **Mail**: Stop resurrecting deleted rows in the mailbox refresh merge
- **Mail**: Keep the `message/rfc822` attachment visible after inline unwrapping
- **Mail**: Strip sender and recipient names from forward-as-attachment filenames
- **Mail**: Open `mailto:` links in the built-in composer
- **Mail**: Spell out the full tag path in drag-and-drop toasts, so `Personal/Receipts` and `Work/Receipts` no longer read as the same tag
- **Mail**: Act on current email state in the context menu's mark-as-read instead of a stale copy
- **Mail**: Match the selected-row tint between dark and light mode
- **Mail**: Restore lost animations after the Tailwind config move
- **Drafts**: Restore the sender identity when reopening a draft
- **Calendar**: Stop re-adding the organizer to the attendee list on every save (#731)
- **Calendar**: Stop re-probing shared accounts that have no calendar access
- **Calendar**: Route the parse dump through the debug logger
- **Contacts**: Stop minting duplicate "Trusted Senders" address books (#730)
- **Contacts**: Hide Contacts and Calendars when the account lacks the JMAP capability
- **Contacts**: Require an explicit shared-account fallback for contacts and calendars
- **Files**: Show the modification date instead of the creation date (#700)
- **PWA**: Honor the configured theme color in the desktop title bar and keep it in step with the active theme (#671)
- **Accounts**: Reconcile the stale persisted account chip after an impersonation handoff
- **Auth**: Only request a credential cookie when the server has a `SESSION_SECRET`
- **JMAP**: Split requests to stay inside the server's advertised limits — `maxCallsInRequest`, `maxObjectsInGet`/`InSet`, `maxSizeRequest`, and concurrency
- **JMAP**: Treat an aborted SSE connect as a close, not a failure
- **JMAP**: Surface the underlying network error cause in passthrough failures
- **Settings**: Avoid leaving `TZ="undefined"` when restoring an unset timezone
- **Plugins**: Stop a privileged plugin from reading another privileged plugin's PRF secret
- **Plugins**: Correct the method names for message errors and `crypto.getPublicKeys`
- **i18n**: Restore key parity across locales and the English `send_timeout` string
- **Docs**: Document the remaining env vars in the env templates, and correct the facts and headings in README and FEATURES
## 1.7.8 (2026-07-22)
### Features
+9
View File
@@ -11,6 +11,7 @@
- Drafts auto-save, keeping the chosen identity, the HTML body, and correct `In-Reply-To` / `References` headers on replies
- Attachments upload, download, drag out to the file system, and preview inline. Images and PDFs render on desktop and mobile, composer attachments open on click, and `.eml` (`message/rfc822`) parts display as a nested email. There are list thumbnails, and a warning when you mention an attachment and forget it.
- Scheduled send, plus a configurable delay before anything leaves the outbox
- Sending without a subject asks for confirmation instead of refusing, and the prompt can be switched off
- Read receipts (MDN, RFC 8098)
- Quoted text lands in an editable island that keeps the original layout
- Full-text search with a JMAP filter panel, search chips, wildcards, OR conditions, and cross-mailbox queries
@@ -19,13 +20,16 @@
- Tags carry color labels, reorder by drag, and can be assigned by dropping a message onto them
- Tags optionally nest: pick a parent when you create one and the sidebar turns them into a tree
- Each tag can be configured to show always, only when there are unread mails or always be hidden
- Tag names and colors live in the browser, while the tags themselves ride on your messages as JMAP keywords. A scan finds keywords no local tag explains and adds them back.
- Star or unstar, with a configurable mark-as-read delay
- Large mailboxes scroll virtually, and the first page of mail prefetches at login
- A refresh button in the list toolbar that spins while the fetch is in flight, alongside the F5 / Ctrl+R / pull-to-refresh gestures it shares a code path with
- Quick reply, hover actions, favicon-based sender avatars, recipient popovers
- Plain-text composer mode and Reply-To
- The signature sits above or below the quoted text, per identity
- Override the From header in the composer. Reply to an alias on a domain you own and it auto-fills as the sender, even when no identity exists for it.
- Import `.eml` files from the folder right-click menu
- Forward a message as an `.eml` attachment, from the viewer or the list right-click menu, named by your filename template
- TNEF (`winmail.dat`) extraction and `message/rfc822` unwrapping
- Folders take an icon, nest, and show counts in the sidebar
- Print from the viewer
@@ -52,6 +56,7 @@
- JMAP sync (RFC 9553 / 9610), falling back to local storage
- Several address books, with drag-and-drop between them
- Groups with member management
- A card can be a person or an organization. Organization cards need no personal name; the org name carries the card and fills vCard's mandatory `FN`.
- vCard import/export (RFC 6350) that flags duplicates
- Trusted senders live in their own JMAP address book
- Autocomplete on To, Cc, and Bcc
@@ -80,6 +85,7 @@
- External content stays blocked until you say otherwise, and trusted senders are remembered
- HTML sanitized through DOMPurify
- S/MIME: manage certificates, then sign, encrypt, decrypt, and verify. Legacy 3DES / PBE is supported, and keys stay isolated per account.
- Add S/MIME or PGP public keys per account, then turn on Stalwart's encryption at rest against one of them. The algorithm, whether new mail is encrypted on upload, and whether spam training runs before encryption are all configurable.
- SPF / DKIM / DMARC indicators surface the most severe SPF result and drop the "via" badge on spoofed mail
- OAuth2 / OIDC with PKCE against Keycloak, Authentik, or the built-in provider, plus OAuth-only mode, OAuth app passwords, and non-interactive SSO for embedded deployments
- TOTP two-factor authentication
@@ -135,6 +141,8 @@
- JSON config can read secrets from files (`passwordHashFile`, `sessionSecretFile`, `oauthClientSecretFile`) for Docker and Kubernetes secret mounts
- An admin toggle controls search-engine indexing (`robots.txt` / `noindex`)
- Plugin system: a schema-driven config UI, render and intercept hooks, `onAvatarResolve`, `onBeforeEmailSend`, composer-sidebar and email-banner slots, calendar event slots, i18n APIs (sandboxed plugins localize through manifest locales and `api.i18n.t`), an `/api/translate` proxy, email-body access, and managed policy enforcement
- Plugin APIs reach contacts (`contact.get` / `create` / `update` / `search`), the signed-in user (`user.getAccounts`, `user.getIdentities`, `user.logout` and a logout hook), and — on the privileged tier — public keys and encryption at rest. Each sits behind its own consent permission.
- `onBeforeBlobUpload` can divert an attachment to external storage before it reaches the server, and `api.http.post` takes binary `Blob` / `File` bodies to get it there
- Plugins hot-reload, load from a dev folder, bundle `src/` on demand through esbuild, and can request `http:fetch` scoped by `httpOrigins`
- Themes upload as ZIP bundles, and admins can enforce one
- An extension marketplace browses and installs plugins and themes from a configurable directory (`EXTENSION_DIRECTORY_URL`). Installing and uninstalling stay in the admin dashboard.
@@ -143,6 +151,7 @@
## Operations
- Progressive Web App: service worker, install prompt, web push for new inbox mail, a dynamic manifest, and install screenshots configurable per domain
- The install prompt and the background-notification prompt are sequenced, so the two never compete for the same moment. Neither appears on login, setup, or settings screens.
- Update checks run on their own, log new releases server-side, and raise a notice that can't be dismissed
- Structured logging (`text` or `json`) with per-category levels
- Anonymous instance telemetry, off unless you enable it through the admin UI, the installer, or `BULWARK_TELEMETRY=on`. It reports version, platform, bucketed account counts, and feature toggles.
+18 -4
View File
@@ -12,7 +12,7 @@ A self-hosted webmail client for [Stalwart Mail Server](https://stalw.art/), bui
[![License: AGPL v3](https://img.shields.io/badge/license-AGPL%20v3-blue.svg?logo=gnu&logoColor=white)](LICENSE)
[![Discord](https://img.shields.io/discord/1482128142939455674?color=7289da&label=discord&logo=discord&logoColor=white)](https://discord.gg/tYCujymGrT)
[![Version](https://img.shields.io/badge/version-1.7.8-green.svg?logo=git&logoColor=white)](CHANGELOG.md)
[![Version](https://img.shields.io/badge/version-1.8.0-green.svg?logo=git&logoColor=white)](CHANGELOG.md)
[![Docker](https://img.shields.io/badge/docker-ghcr.io%2Fbulwarkmail%2Fwebmail-blue?logo=docker&logoColor=white)](https://ghcr.io/bulwarkmail/webmail)
</div>
@@ -157,6 +157,10 @@ OAUTH_CLIENT_SECRET_FILE= # path to a file containing the secret
OAUTH_ISSUER_URL= # optional, for external IdPs
OAUTH_AUTHORIZE_URL= # override only the user-facing authorize endpoint
OAUTH_ALLOW_PRIVATE_ENDPOINTS= # allow discovery to resolve to RFC-1918 addresses
OAUTH_SCOPES= # replace the requested scopes (space-separated)
OAUTH_EXTRA_SCOPES= # append to the defaults instead of replacing them
AUTO_SSO_ENABLED=true # skip the login form, go straight to the IdP
```
Endpoints are auto-discovered via `.well-known/oauth-authorization-server` or `.well-known/openid-configuration`. `OAUTH_ALLOW_PRIVATE_ENDPOINTS` is off by default as an SSRF guard. Enable it only for split-DNS deployments where the issuer's public hostname resolves to an internal IP.
@@ -191,13 +195,18 @@ Credentials are encrypted with AES-256-GCM and stored in an httpOnly cookie (30-
</details>
<details>
<summary>Custom JMAP endpoint</summary>
<summary>Multiple JMAP servers & custom endpoints</summary>
```env
ALLOW_CUSTOM_JMAP_ENDPOINT=true
JMAP_SERVERS=[{"id":"eu","label":"Europe","url":"https://eu.example.com","domains":["example.com"]},{"id":"us","label":"US","url":"https://us.example.com"}]
JMAP_SERVER_AUTO_PICK_BY_DOMAIN=true
```
Shows a "JMAP Server" field on the login form. External servers must CORS-allow the webmail origin.
`ALLOW_CUSTOM_JMAP_ENDPOINT` shows a "JMAP Server" field on the login form. External servers must CORS-allow the webmail origin.
`JMAP_SERVERS` offers a fixed list instead; each entry needs `id`, `label`, and `url`, and may carry `domains` and its own `oauth` block. With `JMAP_SERVER_AUTO_PICK_BY_DOMAIN`, the domain of the address the user types selects the server. The admin dashboard manages the same list — the env form is for stateless deployments.
</details>
@@ -224,6 +233,10 @@ LOGIN_WEBSITE_URL=https://example.com
LOGIN_IMPRINT_URL=https://example.com/imprint
LOGIN_PRIVACY_POLICY_URL=https://example.com/privacy
# Web push goes through a hosted relay, so no VAPID keys or Firebase project
# of your own. Point this at your own relay to opt out. Build-time variable.
NEXT_PUBLIC_PUSH_RELAY_URL=https://notifications.relay.bulwarkmail.org
# Per-domain overrides (optional). When the webmail is served on multiple
# hostnames, each host can override any subset of the branding fields above.
# Match is on the request Host (or X-Forwarded-Host). Use "*.example.com" to
@@ -238,9 +251,10 @@ DOMAIN_BRANDING=[{"host":"maildomain1.com","loginCompanyName":"Company One","log
```env
EXTENSION_DIRECTORY_URL=https://extensions.bulwarkmail.org
PLUGIN_DEV_DIR=../my-plugins # load plugins from disk instead of ZIPs
```
Enables the admin marketplace for browsing and installing plugins and themes.
`EXTENSION_DIRECTORY_URL` enables the admin marketplace for browsing and installing plugins and themes. `PLUGIN_DEV_DIR` is for plugin authors: each immediate subfolder is one plugin with a `manifest.json`, and an entrypoint under `src/` is bundled on demand with esbuild, so editing sources needs only a browser refresh.
</details>
+1 -1
View File
@@ -1 +1 @@
1.7.8
1.8.0
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "bulwark-webmail",
"version": "1.7.8",
"version": "1.8.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "bulwark-webmail",
"version": "1.7.8",
"version": "1.8.0",
"license": "AGPL-3.0-only",
"dependencies": {
"@dnd-kit/core": "^6.3.1",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "bulwark-webmail",
"version": "1.7.8",
"version": "1.8.0",
"description": "Bulwark Webmail - a modern webmail client built for Stalwart Mail Server",
"author": "Bulwark Webmail <bulwark@rbm.systems>",
"license": "AGPL-3.0-only",