The app was locked to portrait in app.config.js and the hand-kept
AndroidManifest.xml. Android 16 ignores that lock on screens 600 dp and
wider, so tablets and foldables rotated into layouts that were never
tested. This removes the lock in both places, keeps React state across
rotation and split-screen resizes (`smallestScreenSize` joins
`configChanges`), and fixes what broke in landscape:
- the thread pager sizes its pages from its own width and snaps back to
the open message after a rotation instead of showing half a neighbour
- compose and the thread view share one keyboard tracker; a rotation
with the keyboard open closes it, since Android sends no new keyboard
frame and the old portrait one blanked the whole landscape composer
- in a short window with the keyboard up the composer hides the format
bar and tightens its header so a few lines of text stay visible
- inputs with suggestions or context around them opt out of Android's
full-screen landscape keyboard
- month views fit whole rows to the real height, keep the month across a
remount, and the month dropdown re-measures and caps its height
- the week grid's header follows the remounted list after a rotation
- the event sheet's actions stay on screen in landscape
- every RN Modal allows all orientations, or iOS forces portrait
Stalwart runs the SMTP RCPT stage while it creates a submission and
records a refused recipient as `delivered: "no"` with its reply: a relay
it doesn't allow ("550 5.1.2 Relay not allowed.") or a used-up throttle
("452 4.4.5 Rate limit exceeded, try again later."), on 0.16 and 1.0
alike. The create still succeeds and onSuccessUpdateEmail files the
message in Sent. The app read only the new record's id and sendAt, said
"Email sent", and on Stalwart destroyed the record right after, the only
trace of the refusal. The message was lost without a bounce. Port of
the webmail's e0b0dfe0.
- the send reads the new submission's delivery status in the same
request (`EmailSubmission/get` of `#sub-1`, its creation id; the
create's own answer has none), also with the retry after a full
submission quota, before the record is destroyed
- every recipient refused: the send fails with the server's reply per
address, the copy filed in Sent is removed and the previous draft
kept, so the composer or the quick reply keeps the text and the
address can be fixed; held sends (undo send, scheduled) are refused
when they are created, so this covers them too
- some recipients refused: the others get the message, and a warning
names the refused ones with their replies
- "Send now" and "Reschedule" check the replacement the same way and
keep the original, which still goes out at its old time, when every
recipient of the replacement is refused; a partial refusal there gets
the warning as well
- the submission prune leaves a shared account that refuses its records
with `forbidden` alone while the app runs, for that login, with a
debug log instead of a warning, and the scheduled list skips it:
0.16.23 lists an account that only shared an address book or a
calendar with the submission capability
`RecipientsRefusedError` and `RefusedRecipient` are added to
`jmap-result.ts`. Five new strings in all 27 languages, four of them
with the webmail's translations.
Stalwart 1.0 counts every EmailSubmission record of an account against
`maxSubmissions` (500 by default), whatever its status or age, and its
own purge of old records never runs. The app never removed a record, so
after about 500 sends from an account every send, quick reply, read
receipt and "Send now" failed with Stalwart's raw "There are too many
email submissions, please delete some" error. This ports the webmail
fix (48382170).
The app now removes the records that can no longer be cancelled.
Destroying a record never stops its delivery, but a pending one could
no longer be cancelled, so a record EmailSubmission/get reports as
pending is never touched:
- an immediate send (no undo delay, no schedule) and a read receipt
destroy their own record right after the send, riding along with the
old-draft cleanup when there is one; only where `urn:stalwart:jmap`
is advertised, and never decided by the created undoStatus, which
0.16.10-0.16.16 report as final for held sends
- a throttled background prune (`src/api/submissions.ts`) destroys
canceled records and final records whose sendAt has passed, going by
EmailSubmission/get, in every submission account; it runs at app
start, on return to the foreground and after sends and undo
- a confirmed cancel (undo, cancel, reschedule, "Send now") destroys
the canceled record in a request of its own
- an `overQuota` on a submission create prunes at once, on Stalwart
walks `EmailSubmission/changes` from "n" for records older than the
query's three-day window, retries once, and otherwise throws
`SubmissionQuotaError`, shown as a translated explanation in the
composer, quick reply, read receipts, the undo bar and the scheduled
list; the copy the failed attempt made is removed as before
0.16 never enforces the limit, and destroy never cancels on any
version, so the same cleanup runs there unchanged.
The undo bar now also says when an undo or "Send now" failed instead
of only logging it. The scheduled list reads every page of
EmailSubmission/query with calculateTotal; it asked for 200 records,
oldest first, so the mail scheduled furthest ahead dropped off once the
three-day window held more than that.
`SubmissionQuotaError` is added to `jmap-result.ts` as a subclass of
`JMAPMethodError`.
The message details panel built its received line, attachment summary
and spam score by gluing strings together; each is now one ICU message
(the attachment count is a proper plural). The SPF/DKIM/DMARC results
use the webmail's translated result names, and an invitation's date is
formatted in the app language instead of always in English.
The quick reply box wrote its own "date, name <email>:" quote header;
it now uses the composer's translated "On {date}, {from} wrote:" line
so both kinds of reply look the same.
The back button, the subject and header star buttons, the sender
avatar and the More/Tag sheet close buttons get screen reader labels,
and the screens i18n test covers the viewer files.
A quick reply held by the undo-send delay could not be undone: the
undo bar lived only on the mail list, and the quick reply never
recorded the held send for it.
- The undo bar is now hosted on every stack screen through the
navigator's `screenLayout`, next to the toasts, and only the focused
screen's renders, so it shows wherever the send started and never
twice. The list's own instance is gone; archive, delete, move and
spam undo use the same bar as before. The composer gets none, since
its Undo reopens the composer.
- The quick reply records a held send through the same store action as
the composer, including the account it went out of, so Undo and
Send now reach a shared account's submission and Undo restores the
reply into that account's Drafts.
- The quick reply dismisses the keyboard after sending, which would
otherwise cover the bar.
Quick replies went out with no signature at all. They are now signed
the way the composer signs a plain-text reply: between the reply and
the quote or at the end, following the signature position setting, with
the "-- " separator when it is on, and with the primary identity's
signature when the sending alias has none of its own.
The quick reply also resolves its sending identity like the composer
(webmail 4fc7b8b5): recipients in To, Cc, Bcc order, and a reply to our
own message from the identity that sent it. It still never takes the
catch-all From rewrite, having no From row to show it.
The viewer fired its store actions with `void` and went back to the
list, so a refused delete, archive, move, spam report, star, tag or
read change failed silently, and nothing confirmed a sent message.
- each viewer action now reports a failure as an error toast, and a
refused star, tag or read change is taken back on screen
- the viewer mounts its own toast host, since the list's sits under it
- an immediate send from the composer or the quick reply box shows
"Email sent"; a send held for the undo delay keeps its undo bar
(webmail `ec67ab99`, `b03a0c1d`)
Stalwart ids are only unique per account. When its opener named no
account, the viewer used the account of the folder open in the list,
and it resolved Trash, Junk and move targets from that folder as well.
Deleting a team message from the Unified Inbox therefore sent
`Email/set` to the user's own account and trashed an unrelated message
with the same id, and a message opened from a notification, deep link
or contact while a shared folder was open went to the shared account.
- the list names the open folder's account when it opens the viewer,
and the viewer takes the account from its opener only, fixed at open
- Trash, Junk, Inbox and move targets come from the message's account,
and delete and move take the message out of its own folder
- the store's delete and move take the viewed message: they only touch
the list's row when the list shows that account, and refuse folders
of any other account
- another account's message is marked read on the server directly
instead of through the open folder's list
- quick reply, unsubscribe and read receipts file into the message's
account's folders
- undo no longer slots another account's message into the open list
- Archive is only offered for mail of the open folder's account, since
it still resolves the archive folder from there
Stalwart advertises `maxDelayedSend` as a fixed 30 days, but its MTA
rejects any hold beyond its `futureRelease` limit, 7 days by default.
Now that scheduled send works on Stalwart, a time 8 to 30 days ahead
passed the checks and then failed with the raw "501 5.5.4 Requested
hold time exceeds maximum of 604800 seconds" reply.
Ported from the webmail:
- on Stalwart the advertised 30 days count as 7
- a submission or reschedule refused for its hold time throws
`ScheduleTooLateError`, and the limit it names replaces the advertised
one for that server
- the composer and the Scheduled screen show "Too far ahead" for it
instead of the SMTP reply
The composer's and the Scheduled screen's presets now only list times
within the limit, and the undo-send hold, from the composer and from
quick reply, is capped at it.
RFC 8621 puts the submission limits (`maxDelayedSend`,
`submissionExtensions`) and the mail limits
(`maxSizeAttachmentsPerEmail`) under each account's
`accountCapabilities`. Stalwart advertises an empty object for them at
session level, which is the only place the client looked, so scheduled
send was refused, the undo-send delay silently fell back to an instant
send, the Scheduled view listed nothing and the per-message attachment
cap was never enforced.
The client now reads these from the account that sends (the account's
own submission capability, else the session's primary submission
account, like the webmail), falling back to the session-level object
for servers that only advertise it there. Quick reply, which can send
from a shared account, now checks that account before holding the
message for the undo-send delay.