Commit Graph
691 Commits
Author SHA1 Message Date
Linus Rath 565d5c1095 feat: choose exact-address or same-domain matching for reply from received address #1000 2026-09-09 19:27:08 +02:00
Linus Rath c395226926 fix: reject wrong passwords server-side so the browser never shows its Basic Auth dialog #969 2026-09-09 19:21:40 +02:00
Linus Rath b91b438076 test: keep stray fetches and timers from leaking across resilience tests 2026-09-09 18:56:51 +02:00
Linus Rath 9796b0b14d fix: index newer settings and flat calendar toggles in the settings search 2026-09-09 18:40:15 +02:00
Linus Rath 8d8ef7e2f1 fix: unreadable native <select> option lists in dark themes #999
The browser paints a native <select>'s option list itself, so the
bg-muted / text-foreground classes on the control never reach it. Themes
whose --color-muted is translucent (Aurora Glass dark uses
rgba(255,255,255,0.05)) composited to a light popup with near-white
text, leaving every unselected option almost invisible.

Pin option background/colour to the popover tokens, which every built-in
theme defines as an opaque surface, and set color-scheme: dark on
selects under .dark so Safari (which ignores option colours) renders a
dark popup too. Fixes all ~40 native selects at once.

Adds a stylesheet test that locks the rules and asserts every built-in
theme's --color-popover stays opaque in each variant.
2026-09-09 18:30:59 +02:00
Linus Rath ae403b06af feat: setting to turn off free scrolling in the calendar 2026-09-09 18:27:01 +02:00
Linus Rath 15a5497a12 feat: freely scrolling month, week and day views #759 2026-09-09 16:38:55 +02:00
Linus Rath 26358c7a63 Merge pull request #991 from rotterp/fix/shared-mailbox-send-identity
fix(composer): send from the address a message was delivered to
2026-09-07 22:38:51 +02:00
Linus Rath d28d8dcd86 fix: report calendar clear failures instead of counting zero #434 2026-09-07 22:34:47 +02:00
Linus Rath 07bbde4786 fix: make the iCal subscription size limit configurable and show the real error #692 2026-09-07 22:34:47 +02:00
Linus Rath 928e2e3794 feat: add a server-side switch for the Stalwart JMAP passthrough #904 2026-09-07 22:34:47 +02:00
Linus Rath e98109b80d fix: require a session for the translate API #903 2026-09-07 22:34:47 +02:00
Linus Rath 4afc2a5db0 fix: surface Email/set failures on delete and move #956 2026-09-07 22:34:47 +02:00
Linus Rath e095805851 fix: use the selected server's issuer for SSO discovery #952 2026-09-07 22:34:47 +02:00
Linus Rath 40e38d1679 fix: retry the JMAP session fetch when a redirect drops the auth header #892 2026-09-07 22:34:47 +02:00
Linus Rath faed1591ef fix: fail fast when the plugin storage database is blocked #840 2026-09-07 22:34:47 +02:00
Linus Rath b4f12b6786 fix: resolve push previews for shared and group mailboxes #839 2026-09-07 22:34:47 +02:00
Linus Rath 2b186910d5 fix: subscribe newly created mailboxes #951 2026-09-07 22:34:47 +02:00
Linus Rath af234f64a4 fix: drop max_age=0 from OIDC re-authentication requests #938 2026-09-07 22:34:47 +02:00
Patrick RotterandClaude Opus 5 4fc7b8b50b fix(composer): send from the address a message was delivered to
On a shared, group or aliased mailbox every reply, reply-all and forward
went out as `identities[0]` - the account owner - whichever mailbox was
open. `autoSelectReplyIdentity` fused two behaviours: matching one of the
user's OWN identities, which never rewrites `From:`, and the domain
catch-all, which puts an address they have not configured into `From:`.
Only the first is safe for everyone, so it is now unconditional; the
rewrite stays behind the setting, which is what its description promises.
`findReplyIdentityId` already implemented that match and was referenced
only from tests.

`forward` is admitted to the match - it was excluded, so a forward from a
shared mailbox went out as the owner - but never takes the rewrite: a reply
continues a thread whose participants know the addressing, while a forward
introduces a rewritten From to a recipient the user just typed. Quick reply
matches own identities only, having no From row to show or correct a
rewrite, and now falls back to the primary's signature as the composer
does, so a shared-mailbox quick reply is still signed.

`findReplyIdentityId` now scans recipients in To, Cc, Bcc order rather than
scanning identities, and prefers an untagged identity over a differently
tagged sibling. Scanning identities let their order decide, and
`sortIdentities` puts the login's own address first - so `To: team@,
Cc: you@` replied as you, the case this is meant to fix.

Automatic selection is restricted to the active account: `composerClient`
follows the chosen identity, and a reply or forward still carries blobIds
only its own account's server can resolve. The dropdown still offers every
account's identities to pick by hand.

New messages are deliberately left gated: `composeFromAccountEmail` falls
back to `AccountEntry.email`, written once at first login, so resolving it
unconditionally would override a user-chosen default sender identity (#507).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:37:29 +02:00
Linus Rath e11e40f0e7 Merge pull request #928 from hildebrandttk/fix/truncated-body-blank-render
fix(email): refetch body value when JMAP truncates the displayed part
2026-09-07 17:55:15 +02:00
Linus Rath b168e45e22 Merge pull request #975 from bartfaizoli76/feature/plugin-dialog-open
feat: api.ui.openDialog + plugin-dialog slot for large, clickable custom UI
2026-09-07 17:42:42 +02:00
Linus Rath 3eeda39d27 Merge pull request #974 from bartfaizoli76/feature/attachment-actions-plugin-slot
Add attachment-actions and composer-attachment-source plugin slots
2026-09-07 17:42:31 +02:00
Linus Rath 93b8d99ff9 fix(): refill missing managed bundles from the server #636 2026-09-07 16:52:20 +02:00
bartfaizoli76 2adc281a9d feat: add ui.openDialog + 'plugin-dialog' slot for large, clickable custom UI
Every existing plugin slot renders wherever it's placed in the page (a
toolbar row, an attachment's hover-action bar, etc.) and is constrained
by that spot's own CSS - fine for small controls, but there's no way
for a plugin to show a large custom UI (a graphical file browser, a
multi-step wizard) since even a position:fixed overlay rendered from
inside such a slot is clipped to the surrounding row's own layout, not
the real page (confirmed live building the webdav-storage plugin: a
folder browser rendered but was squeezed into an unusable sliver).

Adds:
- host-dialog.ts: new 'custom' DialogKind + awaitCustomDialog(), reusing
  the existing confirm/alert/prompt queue plumbing.
- host-api.ts: 'ui.openDialog' API method.
- runtime.tsx: sandbox-side api.ui.openDialog(opts) proxy.
- plugin-types.ts: new 'plugin-dialog' SlotName - a plugin implements
  this slot with its actual custom UI.
- plugin-dialog-host.tsx: renders the requested slot via the existing
  PluginIframeSlot INSIDE the dialog's real app-root fixed overlay
  (position: fixed; inset: 0, above everything) instead of the
  confirm/prompt form, for kind: 'custom'. Resolves via a generic
  onResult callback in extraProps (marshalled the same way
  composer-attachment-source's onAttach already is - no new plumbing
  needed there).

A plugin calls api.ui.openDialog({ slot: 'plugin-dialog', extraProps,
title, width }) and awaits the Promise, which resolves to whatever its
own slot component passes to props.onResult(), or null if the user
closes the dialog without doing so.
2026-09-05 18:57:49 +02:00
bartfaizoli76 06f51486e0 feat: add attachment-actions and composer-attachment-source plugin slots
Two new extension points for third-party attachment/cloud-storage plugins
(e.g. a WebDAV/Nextcloud file browser), neither of which the plugin API
currently supports:

- attachment-actions: a new slot rendered into every attachment's hover
  action row (all six render paths: beside-sender/below-header/mobile,
  each in its compact and expanded-popup form), with the AttachmentInfo
  (name, type, size, blobId, emailId) passed through extraProps. Lets a
  plugin offer a 'save this attachment elsewhere' action next to the
  existing download/preview buttons - previously the only per-attachment
  hook was the read-only onAttachmentDownload observer.

- composer-attachment-source: a new slot rendered in the composer toolbar
  next to the existing composer-toolbar slot, with an onAttach(upload)
  callback in extraProps. Lets a plugin that has already uploaded a file to
  the JMAP server itself (api.jmap.uploadBlob) - e.g. a file picked from an
  external cloud storage browser - have it added to the current draft as a
  real attachment. Previously there was no way for a plugin to add an
  attachment to the draft at all; the closest existing mechanism
  (onBeforeBlobUpload's ExternalAttachmentResult) only replaces a locally
  picked file with body text/a link, it cannot add a brand-new attachment
  from an external source.

Both slots follow the existing PluginSlot pattern (calendar-event-actions):
render nothing when no plugin offers the slot, so this is purely additive.

Motivating use case: the existing nextcloud-attachments community plugin
uploads local files to Nextcloud and appends a share link to the message
body - useful for large files, but there was no way for a plugin to do the
inverse (attach a file that already lives in cloud storage as a real binary
attachment, not a link) or to let attachment recipients save an incoming
attachment back out to their own cloud storage. These two slots make both
directions possible without touching plugin-store or the sandbox bridge -
existing slot/extraProps plumbing (see calendar-event-actions) already
supports arbitrary POJO props.
2026-09-05 11:14:10 +02:00
Stefan Hildebrandt 242fe6aa2d fix(mail): unified mailbox missed accounts that had not connected yet
After a reload the unified mailbox showed only the active account's mail;
other accounts appeared only once visited. Intermittent (~1 in 14), and
not a timeout - nothing on this path uses setTimeout/AbortSignal/race.

checkAuth awaits only the active account and restores the rest in a
fire-and-forget background loop, registering each client only after
connect() resolves. buildUnifiedAccountClients drops accounts with no
live client (`if (!c) continue`). And isConnected was persisted, so it
rehydrated stale-true: the account passed the isConnected filter while
failing the client lookup, and connectedAccountsSignature already looked
complete at mount so nothing re-fired - and the effects keyed on it only
recompute counts, never the list.

Clear isConnected/hasError on rehydrate so both the filter and the
signature describe this session, and refetch the open unified/cross list
when an account joins the connected set (growth only, not on first
render, not while a search owns the list). Extracted
connectedAccountsGrew so the membership check is testable without
rendering MailApp.

Verified the reset cannot block reconnection: checkAuth reads the full
account list and never filters on isConnected.

Fixes #950
2026-09-02 22:15:50 +02:00
Stefan Hildebrandt 2cf7427e32 fix(email): refetch body value when JMAP truncates the displayed part
Large HTML emails (e.g. image-only reports with a data:image src cut
mid-tag by the 256 KB body cap) rendered completely blank because
Email.bodyValues[partId].isTruncated was declared but never acted on.
On truncation, issue one follow-up Email/get with a much larger cap
for the parts actually shown, batched across a thread instead of one
refetch per message.

Closes #884
2026-09-02 08:34:31 +02:00
Linus Rath b5b18371a4 fix: drop unused symbols left by the search dedupe change 2026-09-01 22:16:58 +02:00
Linus Rath bc3b6a0eb6 fix: collapse search hits for the same server object reached through several logins #641 2026-09-01 22:15:49 +02:00
Linus Rath 1d8e4b9d8a fix: duplicate calendar-app import and type errors the stale tsbuildinfo hid 2026-09-01 21:08:10 +02:00
Linus Rath 0c7437f67a feat: open global search hits through the owning login on every surface #847 2026-09-01 20:55:13 +02:00
Linus Rath 0db6bfdc64 feat: global search core: query parser, ranking, cross-account providers #641 2026-09-01 20:55:12 +02:00
Linus Rath a210b22e49 fix: set name.full on all contact write paths so vCards carry mandatory FN #430 2026-08-31 23:53:24 +02:00
Linus Rath 1e9b6ac497 fix: FileNode + blob round-trip in dev mock JMAP, WOPI support for same-origin dev server 2026-08-31 23:45:27 +02:00
Linus Rath 76d67aa1ee feat: add office document fixtures to demo Files and a word-document icon (doc/docx/odt/rtf) 2026-08-31 23:25:05 +02:00
Linus Rath ca7fbbe416 feat: WOPI office document editing in Files (Collabora/OnlyOffice/EuroOffice) #425 2026-08-31 23:16:19 +02:00
Linus Rath 58ebf8d4c5 fix: paginate calendar event fetch so import UID dedup sees all events 2026-08-31 22:48:00 +02:00
Linus Rath d60eb59575 fix: pad attachment preview overlays for the iOS PWA safe area #936 2026-08-31 21:03:08 +02:00
Linus Rath 47dac6421e Merge branch 'main' of https://github.com/bulwarkmail/webmail 2026-08-31 20:43:24 +02:00
Linus Rath a69b3651fd fix: render plain-text-only mail as text in the mobile thread view #489 2026-08-31 20:41:45 +02:00
Michael Richter 84617d6186 feat: OAuth handler for plugins; extended contacts and addressbook API 2026-08-31 09:55:06 +02:00
Linus Rath b11cf4b1a5 feat: offer deleting a non-empty folder with its messages 2026-08-29 18:23:09 +02:00
Linus Rath 03b588096d feat: filter advanced search by message size 2026-08-29 18:20:21 +02:00
Linus Rath cc90903f05 feat: request delivery notifications and REQUIRETLS when sending 2026-08-29 18:16:52 +02:00
Linus Rath e54d179f32 feat: surface CalendarEventNotification invitations and updates 2026-08-29 18:11:50 +02:00
Linus Rath 14cdb2f6ff feat: organize invitations as the default ParticipantIdentity 2026-08-29 18:07:47 +02:00
Linus Rath e8c594001d feat: show attendee free/busy via Principal/getAvailability 2026-08-29 18:03:26 +02:00
Linus Rath 0b39e43a4d feat: surface ShareNotification changes as toasts 2026-08-29 17:59:04 +02:00
Linus Rath 6e5aca60a9 feat: share mail folders with other users via mail:share 2026-08-29 17:53:54 +02:00