You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Email can now be delivered over Resend's HTTPS API instead of SMTP. Set a Resend
API key under Settings → Email and mail goes out over port 443. This exists because several hosting platforms block outbound SMTP on their cheaper plans (Railway below
Pro among them) by dropping the packets rather than refusing the connection - which
looks like a hang, then like a wrong password, and cannot be fixed by changing any SMTP
setting. Ports 25/465/587/2525 are all affected and it is not provider-specific.
The transport follows the credentials you supply: an API key selects HTTPS, otherwise
SMTP, otherwise nothing. It does not probe and silently switch. Settings → Email
badges which path is actually live, so filled-in SMTP fields are never mistaken for SMTP
delivery, and "Remove key" switches back.
Security
All three image uploads now check dimensions before decoding. The 5 MB body limit
bounds bytes on the wire, not pixels: a highly compressed PNG of 30000x30000 is a few
hundred KB and decodes to gigabytes. Both the logo and banner endpoints now read the
image header first and reject anything over 25 megapixels. The branding logo and banner
are admin-only, but the user avatar upload is not - any authenticated member could
send a ~160 KB file that decoded to hundreds of megabytes, and an out-of-memory kill
takes down the process holding the single SQLite connection. It did not need a malicious
user either: a genuine large camera photo is well under 5 MB compressed.
Fixed
Checkbox answers in the admin bookings list are matched liberally. Answers are
canonicalised to yes/no on the way in, but rows created before that landed hold
whatever the surface sent (the embed widget sent Yes), and a strict comparison rendered
those as No - the opposite of what the guest ticked, which matters for consent
checkboxes. Historic rows now display correctly without rewriting stored data.
Branding uploads read the content-type sniff buffer with io.ReadFull. A short read
could hand the sniffer a truncated prefix and reject a valid image.
A failed SMTP dial could hang for ~2 minutes.defaultSMTPTimeout was applied only
after the connection was established, so the dial itself fell back to the OS SYN-retry
limit. Against a host that drops SMTP packets this stalled the background job queue,
which shares a single SQLite connection, delaying every queued email behind it; the
email test button also appeared to hang rather than fail.
The email test button now explains failures instead of reporting "failed to send test
email". An unreachable server names the platform-block possibility and points at the API
key; a timeout after connecting points at the port/TLS mode; provider rejections are
shown verbatim.