- Shipped
- September 3, 2026 at 10:55 PM UTC
- Author
- Kamo
- Commit
- 8c933cb
The email signature footer held one image, named by footer_image_source and sized by a percentage. It now holds a ROW of them: the three built-in sources plus anything the organization uploads, ticked and ordered per scope, sharing one height and one gap. email_signature_badges is the org-wide library. The bytes live in the row rather than in MinIO because a badge has to be fetchable, forever and without a session, by a stranger's mail client — a presigned URL expires and an authenticated proxy 401s — and because it has to be genuinely DELETABLE, which an object in a store nothing is ever removed from cannot be. Uploads are capped at 150px tall, so a row is tens of KB. On the template, footer_badges is the per-scope ordered selection. NULL and '' mean different things and must not be conflated: NULL is 'this row predates badges' and sends the reader to footer_image_source, while '' is 'configured, and none'. The two legacy columns are left exactly where they are — they are the migration source, and nothing writes them any more.