Commit Graph
97 Commits
Author SHA1 Message Date
Stefan HildebrandtandLinus Rath ab3e0e717a feat: email a contact or group via the in-app composer
Adds a "Send email to group" action (To / Cc / Bcc) that opens the composer
pre-filled with the group's members in the chosen field, preserving each
member's display name. It is available both in the group context menu (between
"Edit Group" and "Delete") and in the group detail panel's header (shown when
the group has at least one member with an email). The single-contact "Send
email" button in the contact detail panel uses the same path.

Routing is internal, not via mailto:. Contacts is its own route and the composer
lives in the mail route, so the handoff stashes the recipients
(savePendingMailto) and does a client-side router.push("/"); the main route's
existing consumePendingMailto effect opens the composer in the current account.
This avoids the OS mailto handler (which could open a different mail app) and
the protocol round-trip's full-page reload, which dropped the in-memory
per-account JMAP clients of a multi-account session (a logout).

- contacts/page.tsx: openComposeInApp(recipients, field) shared helper;
  handleComposeGroupFromSidebar (deduped "Name <email>" members, empty -> toast)
  and handleComposeContact; wired to the sidebar, group detail, contact detail.
- contact-group-detail.tsx: onComposeGroup(field) prop + To/Cc/Bcc header control
  (shown when the group has emailable members).
- contacts-sidebar.tsx: onComposeGroup(groupId, field) prop + "Send email to
  group" submenu between Edit and Delete.
- contact-detail.tsx: onCompose() prop; the button is no longer a mailto: link.
- mailto.ts: recipient splitter is quote-aware (reuses the composer's
  splitRecipients) so a comma in a display name survives — still useful for real
  OS mailto: links.
- i18n: contacts.groups.send_email{,_to,_cc,_bcc} and no_member_emails across all
  locales.

Display names round-trip via formatRecipient -> parseRecipientList.
2026-06-19 12:29:43 +02:00
Linus Rath 1f889b0965 Merge branch 'main' of https://github.com/bulwarkmail/webmail 2026-06-15 23:16:10 +02:00
Linus Rath 0b9fe5451f fix: preserve line breaks in generated text/plain alternative #421 2026-06-15 23:15:04 +02:00
Stefan HildebrandtandLinus Rath 94b1f5aa48 refactor: model composer recipients as arrays instead of delimited strings
Alternative to the quote-aware string fix: represent committed To/Cc/Bcc
recipients as Recipient[] ({name?, email}) with a separate input-text
string per field, instead of a single comma-joined string parsed with
split(','). Structured recipients can never be torn apart on a delimiter,
so a display name containing a comma ("Doo, John <john@doo.org>", as
produced on Reply-All) stays a single chip.

- email-composer-utils: add Recipient type, parseRecipient/formatRecipient,
  and parseRecipientList/formatRecipientList for the (de)serialization
  boundary (ComposerDraftData stays a string; quoting keeps it lossless).
  Remove the now-unused string-chip helpers.
- email-composer: to/cc/bcc are Recipient[]; toInput/ccInput/bccInput hold
  the in-progress text. Reply/forward init, autocomplete, chip edit, drag &
  drop (payload now carries the structured recipient), send/draft/validation
  and template paths all operate on arrays. withInput() folds uncommitted
  typed text into the send/validation set.
- Tests updated for the array contract; add comma-in-name chip coverage.
2026-06-15 22:59:46 +02:00
Stefan HildebrandtandLinus Rath 1ebfb286ad feat: drag and drop recipient chips between To/CC/BCC fields
Adds native HTML5 drag-and-drop so users can move recipient email
address chips between the To, CC, and BCC fields in the composer.
Chips dragged onto the Cc/Bcc toggle buttons auto-reveal the hidden
field and place the chip there.
2026-06-15 15:23:00 +02:00
Linus Rath 1e63e2469a fix: strip build-time basePath from router.push redirects after login #390 2026-06-12 00:23:00 +02:00
Linus Rath a4f476945d feat: JMAP file/folder sharing in Files app #408 2026-06-12 00:02:45 +02:00
Linus Rath be58cee989 fix: dedupe scheduling emails, Stalwart-compatible calendar filters 2026-06-11 18:24:43 +02:00
Linus Rath 9863b9d88e feat: add Aurora Glass built-in theme 2026-06-03 19:30:51 +02:00
Linus Rath 31100b8f87 fix: discover OIDC metadata server-side to avoid CORS failures #382 2026-06-02 00:15:50 +02:00
Linus Rath 152ec99262 feat: add Elastic built-in theme 2026-06-01 23:28:15 +02:00
Linus Rath ce401c0f59 test: cover withBasePath base-path fallback prefixing 2026-06-01 17:59:19 +02:00
Linus Rath 3035fb046f feat: surface most severe SPF result and hide "via" badge on spoofed mail 2026-06-01 17:46:57 +02:00
Linus Rath 6ee3849463 fix: theme plugin slot iframes with host font + color tokens 2026-05-31 16:28:22 +02:00
Linus Rath ae66f8d89d Feature: per-viewer colors for shared calendars (#345) 2026-05-31 15:52:27 +02:00
196e51e91b fix: preserve HTML signature when sending a quick reply
The quick-reply box built its body with appendPlainTextSignature, which runs
the identity's HTML signature through htmlToPlainText, and sent a text-only
message (htmlBody was undefined). A formatted signature (e.g. <strong>…) was
therefore flattened to plain text in the sent mail, even though it previewed
correctly in the identity editor. The full composer already builds an HTML
signature block; quick reply did not.

Add an appendHtmlSignature helper (mirrors the composer's send-time block) and,
when the sending identity has an HTML signature, send a matching HTML body from
handleQuickReply so the markup is preserved. Text-only identities keep the
plain-text-only behavior.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 15:12:30 +02:00
Linus Rath 1da04c254b feat: per-domain branding overrides on /api/config, manifest, pwa-icon #332 2026-05-28 20:06:47 +02:00
31e96d6a46 Feat: Scheduled send and send delay #322
* ADD DOC

* Scheduld Send

* add new shortcuts

* fix

* fix

* fix bugs

* rework

* fix draft duplicating

* fix err

* some fixes

* fixes from review

* fixes from review

* fixes from review

* disable password managers for recipients

* fix email store lazy load

* add translations

* fix styling

* fixes

---------

Co-authored-by: Linus Rath <139418639+rathlinus@users.noreply.github.com>
2026-05-28 18:46:49 +02:00
Linus Rath 63f2169ae7 fix: add OAUTH_ALLOW_PRIVATE_ENDPOINTS for split-DNS setups 2026-05-22 17:22:14 +02:00
Linus Rath ac4a89120d fix: preserve inline images when replying #163 2026-05-22 12:06:55 +02:00
Linus Rath 1c02970ae1 fix: use canonical INBOX in Sieve filter paths #313 2026-05-22 11:51:25 +02:00
Linus Rath fc5f6f43d6 feat: expose PWA, app identity, and extension directory keys in JSON config #312 2026-05-21 23:35:58 +02:00
Linus Rath ecd0467ffa fix: stop pulling node:dns into client bundle via OAuth discovery 2026-05-18 19:31:38 +02:00
Linus Rath fa261fecfd fix: omit empty cc/bcc from Email/set so server does not emit bare Cc: header #301 2026-05-18 16:36:45 +02:00
Linus Rath f134766fd1 fix: validate OAuth discovery endpoints against SSRF 2026-05-18 12:53:43 +02:00
Linus Rath 088810bd20 feat: harden plugin sandbox and migrate in-tree plugins 2026-05-18 12:17:54 +02:00
Linus Rath 92127e2f00 fix: allow table-based layouts in HTML signature sanitizer 2026-05-18 00:24:08 +02:00
Linus Rath 307e6d5d34 fix: warn + block install when app version is below plugin's minAppVersion 2026-05-16 18:11:52 +02:00
Linus Rath ca1108f455 feat: master-user impersonation route + app-top-banner plugin slot 2026-05-16 17:59:07 +02:00
Linus Rath b725000f4d feat: implement vCard 4.0 parsing and generation support 2026-05-15 20:10:18 +02:00
Timo StreuleandLinus Rath 55a408e810 feat: allow img in HTML identity signatures
- Restricts src to https: URLs or base64-embedded raster data: URIs (png/jpeg/gif/webp).
- SVG is excluded for safety reasons.
- Images with a disallowed src are removed entirely so they don't render as broken-image icons.
2026-05-15 14:46:43 +02:00
Lucas GaitzschandLinus Rath 3f444a8912 Feature/protocol handlers
* Added account selection for protocol links when multiple connected accounts are available, including mailto: links
* Added support for handling mailto: links in an already-open PWA/session instead of always opening a new tab
* Added webcal: protocol handling for calendar links
* Added account selection for webcal: links when multiple calendar-capable accounts are connected
* Added an import-or-subscribe choice for detected webcal calendars
* Added protocol handler settings for registering mail and calendar handlers and choosing the open mode
* Added service worker/session coordination for passing protocol requests between browser/PWA contexts
* Added tests and translations for the new protocol handler flows
2026-05-12 20:49:05 +02:00
Augustin MarcinandLinus Rath b0640c9ecc feat(compose): From override + catch-all auto-reply (fixes #246)
Adds an Override toggle in the composer's From row. When enabled, name
and address become free-text inputs. Mail is still submitted through the
selected identity, but the outgoing message's From: header — and the
SMTP envelope MAIL FROM when different — is set from the override.

The existing "Auto-select Reply Address" setting is extended: if the
incoming message was addressed to an alias on a domain that matches one
of your identities but isn't itself an identity (classic domain catch-
all), it now auto-enables Override and pre-fills the alias. Quick reply
honors the same resolution. The setting is relabeled to reflect the
broader behavior.

JMAP: client.sendEmail gains an optional envelopeMailFrom; when set, the
EmailSubmission includes an explicit envelope with that mailFrom and the
to/cc/bcc as rcptTo so header-From and envelope can diverge (JMAP §7.3).

S/MIME: override is incompatible with sign/encrypt and is refused with a
clear error — signing a different visible From from the identity's
certificate Subject would produce messages clients reject.

Tests: resolveReplyFrom covers exact match, sub-address stripping,
catch-all detection, identity preference, and foreign-domain null.
2026-05-11 12:13:47 +02:00
Linus Rath 178922323d chore: update version to 1.6.2 2026-05-06 20:07:36 +02:00
Linus Rath ec0f355c13 feat: allow custom sub-addressing delimiter character #239 2026-05-01 01:48:39 +02:00
Linus Rath c555973b6b feat: configurable sub-addressing delimiter #239 2026-05-01 01:42:06 +02:00
Linus Rath 45a4db1c22 fix: pin JMAP auth verification to configured server URL #237 2026-04-30 15:34:14 +02:00
Linus Rath 7188abc9bc fix: set In-Reply-To and References on replies #234 2026-04-30 01:25:04 +02:00
Linus Rath 1b84547211 feat: add Theme API v2 with token compiler, skin slot 2026-04-28 15:39:13 +02:00
Linus Rath 3043639d2d fix: validate URLs before outbound fetch 2026-04-27 22:23:39 +02:00
Linus Rath 3e1de10213 feat: add JMAP sharing for calendars and address books 2026-04-26 20:10:04 +02:00
Linus Rath aadf56c27b fix: emit RFC 9553 name kinds and decode QUOTED-PRINTABLE in vCard import #224 #187 2026-04-26 02:47:19 +02:00
Linus Rath d657aec391 feat: add support for right-side composer sidebar and update related types 2026-04-25 19:45:45 +02:00
Linus Rath fe1d4861bb feat: composer-sidebar slot + plugin-declared frame-src origins 2026-04-25 18:40:54 +02:00
Linus Rath 794001fdbd feat: migrate Stalwart management API to JMAP x: methods (0.16)
Drops the 0.15 REST management API and routes all account/auth/crypto/
principal operations through Stalwart 0.16's schema-driven JMAP
endpoint via a single passthrough (/api/account/stalwart/jmap).

- New client helper `stalwartJmap` + typed `requireResult`
- account-security-store rewritten against x:AccountPassword, x:AppPassword,
  x:AccountSettings, x:Account (with currentSecret for TOTP ops)
- Client-side TOTP setup via `otpauth`; server-generated app password
  secrets shown once on create
- Admin check switched to /api/account permissions
  (sysAccountQuery/sysTenantQuery/sysSystemSettingsGet)
- Removed sieve vacation-overwrite workaround (fixed upstream #1251)
- Deleted old REST routes, StalwartClient, stale tests; added new
  tests for passthrough + store
2026-04-21 17:29:23 +02:00
Linus Rath f05f70a9e5 fix: prevent XSS via quote injection in plain-text email linkifier 2026-04-18 00:35:21 +02:00
Linus Rath 8bdadc7ba3 fix: standardize punctuation 2026-04-16 19:07:42 +02:00
Linus Rath 31eff96614 feat: Enhance external rule handling in Sieve parser and store #201 2026-04-16 17:22:52 +02:00
Pascal DietrichandLinus Rath f9052eb23f feat: add SESSION_SECRET_FILE and OAUTH_CLIENT_SECRET_FILE env vars 2026-04-09 22:13:08 +02:00
Linus Rath 9ee25c930e fix: compute per-occurrence utcStart/utcEnd in recurrence expansion #116 2026-04-02 13:35:26 +02:00