Every Web Push to an iPhone or a Mac was refused, silently as far as the person
waiting for the reminder could tell. The cause was the VAPID "sub" claim: on an
instance with no mail configured it fell back to mailto:verdande@example.invalid,
and Apple answers 403 Forbidden to a mailto whose domain is made up. Verified
against web.push.apple.com on the live subscriptions — that mailto gets a 403, the
instance's https URL a 201.
So the subject is now a real mailto when SMTP.From is a real address, and otherwise
the instance's own https base URL — which is a valid VAPID subject, points at
something that exists, and every push service including Apple accepts.
Two things found alongside it, both fixed:
- A successful push did not clear the failure count. A subscription drops at ten
failures, and all four live ones sat at nine from this bug — one flaky push from
being deleted despite working. MarkPushDelivered zeroes the count and moves
last_used_at on every delivery, so a subscription that recovers is not still
carrying its old failures toward the cliff.
- A reminder with no project made a notification whose URL was "/projekt/" — a
dead link. Empty project now points at the app root.
Test: the subject is a real mailto when there is one, and the https URL when there
is not — including for the localhost default, which is not a real address.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>