Commit Graph
528 Commits
Author SHA1 Message Date
Linus Rath a2e36e6e86 fix: open read-only documents in ONLYOFFICE without the -103 warning #1187 2026-10-08 14:32:39 +02:00
Linus Rath cd3099e1f6 Merge pull request #1186 from oguzyilmaznet/feat/tab-title-account
feat: name the account in the tab title, and let operators keep the subject out
2026-10-07 19:33:23 +02:00
Linus Rath 832651bcaf fix: include sent mail when searching from unified all mail 2026-10-07 19:28:44 +02:00
Linus Rath 8889346371 feat: warn when a message's sender can't be verified 2026-10-07 19:04:15 +02:00
Oğuz YılmazandClaude Opus 5.5 54ec8c6584 feat: let operators keep the message subject out of the tab title
Opening a message puts its subject in the browser-tab title. The title does
not stay in the tab strip: browsers keep it in history and in the
session-restore list, and screen shares show it. For mailboxes that hold
other people's correspondence that is a leak nobody audits.

A new feature gate, tabTitleSubjectEnabled ("Subject in Tab Title" under
Admin -> Policy), is on by default, so nothing changes for existing
installs. With it off, the title names the folder instead, so the tab still
says where you are. It is an admin gate rather than a user setting: whose
mail the boxes hold is a deployment decision.

The gate counts as off until the policy has loaded, so a subject never
slips into history while the setting is still unknown.

Refs #1159

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 08:26:51 +03:00
Oğuz YılmazandClaude Opus 5.5 8ca7dbbe9b feat: name the active account in the browser-tab title
The tab title was "<context> - <app>", so two mailboxes open side by side
read the same in the tab strip and in the browser's session-restore list.

It is now "<context> - <account> - <app>", the order Gmail and Outlook Web
use: browsers cut a long title from the end, so the part that changes comes
first and the app name last. There is no setting for it; the account is what
tells the tabs apart.

The formatting, and the mail view's choice of context (composer, then
message, then mailbox), live in lib/tab-title.ts with tests. The mail view
sets its title through useDocumentTitle(), which other surfaces can use too.
Next renders the root layout's metadata <title> again on every client-side
navigation, after the surface has mounted; the hook puts its title back when
that happens. Only the surface that set the title last does so, so two
titles never fight.

Refs #1159

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 08:26:23 +03:00
Linus Rath 9881c20ddd fix: keep Stalwart as the authenticator entry name on unbranded installs #1177 2026-10-06 23:29:42 +02:00
Linus Rath cbfcdf3b69 Merge pull request #1152 from dealerweb/feat/rule-periods-out-of-office
feat: out of office forwarding and recipients, filter rule periods
2026-10-06 23:28:58 +02:00
Linus Rath e731c0849d Merge pull request #1184 from gwku/fix/pointer-cursor
fix: show the pointer cursor on buttons and other controls
2026-10-06 23:28:56 +02:00
Linus Rath 898e250a6a Merge pull request #1175 from cybersmurf/fix/calendar-agenda-shared-accounts
fix: show shared and group calendars in the Calendar Agenda
2026-10-06 23:28:54 +02:00
Linus Rath 9738231c2a fix: stop stale tabs and devices from dropping synced templates 2026-10-06 22:14:29 +02:00
Gerwin Kuijntjes 682fc086d1 fix: show the pointer cursor on buttons and other controls
Tailwind v4's preflight no longer gives buttons a pointer cursor, so most
buttons, menu items, tabs, switches and selects showed the arrow. A base-layer
rule in globals.css gives them the pointer again and gives disabled ones
not-allowed. Cursor utilities on components still take precedence.
2026-10-06 21:31:11 +02:00
Linus Rath 1e10aa9bd6 feat: move several folders at once from the folder settings #1173 2026-10-06 15:49:53 +02:00
sudandClaude Fable 5.1 61fc130a74 fix: show shared and group calendars in the Calendar Agenda
The agenda sidecar queried only the session's primary calendar account,
so events in a shared or group account (a family or team calendar) never
reached the Calendar Agenda plugin, although the calendar app shows them.

Read every account the calendar app reads: the primary account plus
accounts that advertise the calendar capability or are not personal,
mirroring the client's getCalendarCapableAccountIds(). Event and
calendar ids repeat across accounts, so the DTO id is scoped as
<accountId>:<id> and carries accountId; calendar colours are looked up
per account. A shared account whose calendars cannot be read is skipped
instead of failing the whole agenda; a failure of the primary account is
still reported.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 06:24:17 +02:00
Linus Rath 85b3bb86ed fix: keep the meeting link when duplicating an event #1170 2026-10-05 23:09:48 +02:00
Linus Rath 7e1a659c06 fix: open the WOPI editor behind a reverse proxy with split addresses #1130 2026-10-04 22:16:29 +02:00
Linus Rath a4e313f73e fix: leave trash and spam out of tag views and their counts #1156 2026-10-02 23:15:26 +02:00
Linus Rath c317cd9679 fix: offer the shared account's folders first when moving its mail #1149 2026-10-02 23:04:28 +02:00
Linus Rath 0b4d0b0f3c feat: limit the day and week views to working hours and days #1164 2026-10-02 22:56:16 +02:00
Linus Rath 0e39b199a1 feat: link the running build's source from the About card #1161 2026-10-02 22:10:29 +02:00
Linus Rath cbde644441 fix: show why the server refused a sent message instead of a dangling reference error 2026-10-02 22:02:50 +02:00
Linus Rath 64b39c504a fix: open the inbox instead of the last folder when the app starts
The boot snapshot restored the last plain folder that was open, and
unified views are never written to it. A session that touched Trash and
then moved to the unified inbox therefore opened Trash on every visit to
`/`. A plain visit now starts in the account's own inbox and drops rows
cached for another folder; reloading a `/mail/folder/...` link still
continues in that folder.
2026-10-02 16:31:44 +02:00
dealerweb f5fb7f9db9 feat: out of office forwarding and recipients, filter rule periods
Filter rules can be limited to a period: the rule dialog takes a start
and an end on the user's clock, the rule list shows whether a rule is
planned, active or expired, and the script tests the moment of
delivery with RFC 5260 currentdate in UTC. A rule is never written
without its period.

The vacation card becomes an out of office page: the period on top,
then the automatic reply and forwarding, each with its own switch.
Forwarding runs with or without the auto-reply, within the period,
never for spam, and keeps a copy here or not. Against the server's
redirect limit it counts as a rule ahead of all others, one that stops
the message unless it keeps a copy. The auto-reply can go to
internal or external senders only, told apart by the envelope sender
against the account's own domains. Both run from the filters script
that includes Stalwart's vacation script, which is put back in charge
when the server's own script takes over.

A script that uses any of this says metadata version 2, which older
builds leave alone instead of writing it back without these fields.
2026-10-02 11:29:32 +02:00
Linus Rath 71a1fad77b fix: keep a copied message's original date in the other account #1150
A copy between logins goes through `Email/import`, which sent no
`receivedAt`, so the server stamped the import time and every copied
message landed at the top of the destination folder as today's mail.
`importRawEmail` now takes the original `receivedAt` (the same change
#1151 carries), and the cross-account copy and move pass it.
2026-10-02 10:35:09 +02:00
Linus Rath 9ee463084d Merge pull request #1150 from lucamzanon/feat/cross-account-copy
feat: copy messages to a folder of another connected account
2026-10-02 10:33:15 +02:00
Linus Rath 07625bc513 fix: show the translated check-your-Sent message for an unconfirmed send #1019
A send answered without an EmailSubmission threw a fixed English
message, which the composer showed as is in every language. It now
throws `SendUnconfirmedError`, and the composer shows the existing
`send_timeout` text, the same advice as for a send whose answer was
lost: check Sent before sending again.
2026-10-02 10:33:10 +02:00
Linus Rath dfa82f7cca Merge pull request #1019 from lucamzanon/fix/compose-error-recovery
fix: keep the draft when a send is not confirmed
2026-10-02 10:32:27 +02:00
Linus Rath 39efd8af3c fix: preview the named message when the inbox lookups beside it fail #1041
Any failed method in the preview request answered 502, so when the
server named the delivered message and it was read fine, a failing
Inbox query still turned the notification into a generic "New mail".
The named message is now a complete preview on its own.

A response without the optional `total` was also treated as a failure;
it now counts the returned ids.
2026-10-02 10:32:22 +02:00
Linus Rath 86afe94204 Merge pull request #1041 from lucamzanon/fix/web-push-recovery
fix(push): keep notification previews truthful when a lookup fails
2026-10-02 10:31:37 +02:00
Linus Rath 7eced91f82 fix: keep retrying a lost push subscription, at most every 15 minutes #1147
Recreating the subscription removed the account's stored id before the
replacement was created and verified, and the resync now requires that
id. One interrupted or timed-out attempt (up to 75 seconds of
verification) therefore ended recovery for that account for good. The
id now stays until a verified replacement overwrites it.

A failed resync also forgot its timestamp, so every return to the tab
reran the whole enable. It now waits 15 minutes before the next try.
2026-10-02 10:31:33 +02:00
Linus Rath 5d6bd51331 Merge pull request #1147 from lucamzanon/fix/push-resubscribe
fix(push): recreate a browser subscription that was lost
2026-10-02 10:30:43 +02:00
dealerweb f4b5027733 fix: keep the group labels of native option lists readable in dark themes
The From dropdown groups the identities by account. #999 gave the
options the popover colours, but the group labels kept the control's
text colour on the popup's base, which a transparent control leaves
light: in dark themes, light text on a white bar.
2026-10-01 17:31:59 +02:00
lucamzanon f02dbf3a40 feat: copy messages to a folder of another connected account
With several accounts connected, mail could only be moved between
them (drag to another account's folder). There was no way to file a
copy in another account and keep the original where it is.

crossAccountMoveEmails and copyEmailAcrossAccounts take an optional
`{ keepOriginal: true }`. With it the source message is not destroyed,
and the store leaves the list, the open message and the selection as
they are; only the destination's folders are refreshed. Without it
nothing changes.

The message menu gets "Copy to account..." when more than one account
is connected. It lists the writable folders of the other accounts
(their folder lists are fetched when the menu opens) and copies the
selection, or the message the menu was opened on, through the new
copyEmailsToAccount action. That groups the messages by the login and
JMAP account they live in and refuses a copy into the account a
message is already in.
2026-10-01 12:53:14 +02:00
lucamzanon 4bc5d48888 fix(push): keep notification previews truthful when a lookup fails
A JMAP method error comes back with HTTP 200. The preview route read a
failed Mailbox/query or Email/query as an empty Inbox and answered
"nothing unread", so the service worker dropped the push in silence.
It now answers 502, and the worker shows its generic notification.

When the server names the message that arrived and it cannot be read -
deleted since, or filed where this login cannot see it - the route no
longer substitutes the newest unread message in the Inbox, which was
some other mail announced as if it had just arrived. It names no
message; the unread total still comes back for the generic toast.
2026-10-01 12:44:14 +02:00
lucamzanon 3cfab390a0 fix(push): recreate a browser subscription that was lost
The background re-sync skipped any account whose browser subscription
was gone (isWebPushEnabled needs a live one), which is exactly the
state that needs repairing: the browser or the user cleared the
endpoint while the opt-in and the server registration survived, and
push stopped for good. It now runs whenever the user opted in and
permission is granted, so the normal enable flow recreates the
subscription. It still never prompts. A failed attempt no longer waits a
day for the next one.
2026-10-01 12:42:34 +02:00
lucamzanon 15740fa286 fix: keep the draft when a send is not confirmed
When the response carries no EmailSubmission - a method error, or no
answer for it at all - nothing confirms the message left, yet the send
went on as if it had: the old draft was replaced and the composer
closed. It now fails with "Send confirmation was not received" and
keeps the draft, so the user can check Sent before sending again.

An empty notCreated map is a success some servers spell out; it is no
longer read as a failure.
2026-10-01 12:12:46 +02:00
Linus Rath 90c8195a00 Merge pull request #1134 from dealerweb/feat/recipient-mentions
feat: mention a recipient by first name with @ in the message body
2026-10-01 11:06:00 +02:00
Linus Rath 868805ec9a fix: keep ringing for a second mail in the same account #1141
The quiet window ignored which account rang, so a second, different
message in the same account within 30 seconds arrived without sound, and
every single-login user lost the alert too. The window now records the
account of the last audible alert and silences only other accounts,
which is the burst across logins the change is meant for.
2026-10-01 11:02:39 +02:00
Linus Rath fa45ff997f Merge pull request #1141 from lucamzanon/feat/push-quiet-window
feat(push): ring once for a burst of mail across accounts
2026-10-01 11:02:33 +02:00
Linus Rath 6bce3323a9 fix: keep previews that only start like a style sheet #1136
The leading-CSS strip emptied or cut ordinary previews:
"@media team, the brief is attached", "@Page can you check?" and
"@import the CSV ..." became empty, and "Reminder: your appointment
{date: 2026-10-01} is confirmed" became "is confirmed".

At-rule names now match in lower case only, only `@import` and
`@charset` end at a semicolon, an at-rule word with no block after it
is prose, and a selector colon must not be followed by a space.

The conversation view's collapsed cards, contact activity, the pro
folder tab and the list's row-height estimate now use `cleanPreview`
too, so they agree with the list rows. The test's invisible characters
are written as escapes.
2026-10-01 11:02:26 +02:00
Linus Rath 1a186f8962 Merge pull request #1136 from lucamzanon/fix/preview-leading-css
fix: skip a style sheet at the start of a message preview
2026-10-01 11:01:28 +02:00
lucamzanon cd39805566 feat(push): ring once for a burst of mail across accounts
Each account has its own notification, so one message reaching several
of the user's accounts rang once per account. Only the first alert in a
30 s window makes a sound now; the others still appear or update,
silently. The window runs from the last audible alert, so a steady
trickle still rings every so often.
2026-10-01 04:40:08 +02:00
lucamzanon 717f18fc46 feat(unified): say how many accounts the unified mailbox holds while logins reconnect
After a load the logins other than the one on screen reconnect in the
background, and until they are all back the unified counts cover only
some of them. With many logins that lasts seconds, and a partial total
looks exactly like the whole one.

While that restore runs, the "All accounts" header shows how many logins
are already in the scope, e.g. "4/10", with a translated label for screen
readers. It goes away when the scope is complete or the restore is over -
a login that failed to reconnect does not keep it up.

`restoringAccounts` in the auth store marks the background restore; the
count itself is a pure function with its own tests.
2026-10-01 04:38:04 +02:00
Linus Rath 2cbf73ed08 test: expect session URLs hosted on another origin to be kept 2026-10-01 00:36:00 +02:00
Linus Rath 29c74c3b77 feat: sign in with an access token 2026-10-01 00:24:47 +02:00
dealerweb 2b5110e0e4 feat: mention a recipient by first name with @ in the message body
Typing @ at the start of a word in the rich-text body offers the To and
Cc recipients (contact groups expanded) and inserts the chosen one's
first name as plain text. The name comes from the display name; with a
firstname.lastname@ address, the address tells which word of the name is
the first name, and without a name the address supplies it. A bare
initial keeps the mailbox name (@m.mustermann), and recipients who share
a first name get their full name. Bcc recipients are never offered -
naming one in the text would disclose them to everyone else.

The list only opens while a recipient matches, so Enter and Escape
otherwise keep their usual meaning. While it is open, Escape closes the
list rather than the composer, which handles Escape in the capture phase,
and the list closes when the editor loses focus.

Built on @tiptap/suggestion, at the version of the other TipTap packages.
2026-09-30 22:43:59 +02:00
lucamzanon 2d521d19b2 fix: skip a style sheet at the start of a message preview
Some servers build a message's preview from its HTML body without skipping
the <style> element, so a marketing mail's preview - in the list and in its
push notification - can read "@media screen and (min-width:600px){.hide{
display:none!important;…" and never reach the text.

Drop whole leading rules from the preview before showing it; a preview that
ends inside the style sheet was nothing but CSS and becomes empty, so the
usual "no preview" text shows instead. A rule only counts as CSS when its
block holds declarations or further rules, so prose with a brace in it
("the meeting is at {time} tomorrow") is left alone.
2026-09-30 21:35:20 +02:00
Linus Rath 2d2b0753be Merge pull request #1132 from lucamzanon/perf/multi-account-startup
perf: stop the startup request storm with many logins
2026-09-30 20:33:32 +02:00
Linus Rath cd14807133 Merge pull request #1112 from theLucius7/fix/config-load-recovery-20260927
fix: recover from transient application configuration failures
2026-09-30 20:32:44 +02:00
Linus Rath 692be6aa9d Merge pull request #1095 from lucletoffe/fix/calendar-location-links
fix(calendar): surface the meeting link and open the location in maps
2026-09-30 20:32:44 +02:00