Files
webmail/lib/send-failure-message.ts
T
Linus Rath 483821706d fix: keep sending working past Stalwart 1.0's submission limit
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. Bulwark never destroyed a
submission, so after about 500 JMAP sends an account could not send at
all: every send, read receipt and reschedule failed with a raw "There
are too many email submissions" error, and each failed attempt left one
more copy of the message in Drafts.

Bulwark 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 pending records are never touched:
- an immediate send (no hold, no undo window) destroys its own record
  right after the send, riding along with the old-draft cleanup; 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 destroys canceled records and final
  records whose `sendAt` has passed, going by `EmailSubmission/get`, in
  every submission account; it runs at startup, after sends, after
  undo and on EmailSubmission state changes
- a confirmed cancel (undo, cancel, reschedule) destroys the canceled
  record in a request of its own
- an `overQuota` on a submission create prunes at once, on Stalwart
  walks the change log 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 and the scheduled-send actions

Failed sends now clean up after themselves and say so:
- a failed send removes the Drafts copy it created and keeps the
  user's draft; the raw send paths remove their import the same way
- a read receipt that did not go out is taken back out of Sent, a
  method-level error counts as a failure, `$MDNSent` is only set after
  a sent receipt, and the automatic receipt no longer retries on every
  refresh of the open message
- quick-reply failures, "Send now", "Reschedule" and a failed undo are
  shown instead of only logged
- the scheduled list reads every page of `EmailSubmission/query`; it
  stopped after the first because `total` needs `calculateTotal`
2026-09-25 17:33:31 +02:00

21 lines
1.1 KiB
TypeScript

import { RequestTimeoutError, ScheduleTooLateError, SubmissionQuotaError } from '@/lib/jmap/client';
/**
* What to tell the user about a send (or reschedule) that failed, from the
* `email_composer` messages. Most errors carry the server's own description;
* these are the ones it would misrepresent or leave unexplained:
* - a full submission quota: Stalwart asks the user to "delete some", but
* the client has already removed every record it may, so only an
* administrator can help;
* - a timeout, which is not a clean failure: the submission may have reached
* the server and gone out, with only the answer lost. Saying "send failed"
* would invite a re-send and a duplicate, so point at Sent instead (#702);
* - a hold beyond the server's limit.
*/
export function sendFailureMessage(error: unknown, t: (key: string) => string): string {
if (error instanceof SubmissionQuotaError) return t('submission_quota');
if (error instanceof RequestTimeoutError) return t('send_timeout');
if (error instanceof ScheduleTooLateError) return t('schedule_send_too_late');
return error instanceof Error && error.message ? error.message : t('send_failed');
}