feat: attach a self-describing ticket card to the email (v1.6.1-aio.10) #43

Merged
padreug merged 2 commits from feat/ticket-card-attachment into main 2026-09-08 14:53:06 +00:00
Owner

Why

After #42 the ticket mail scored 8.4/10 on mail-tester; the last deduction was HTML_IMAGE_ONLY_08 (1.8) — an HTML part whose only content of note is a remote <img>. Two more reasons to change how the QR travels: most clients block remote images until the reader opts in, and a bare QR saved from the mail says nothing about what it opens.

What

  • qr.py (QR + logo helpers moved out of views_api.py) gains render_ticket_card: site title, event name, when/where, the branded QR, name on ticket, ticket id, door instruction. Laid out with DejaVu Sans, bundled under static/fonts/ with its licence — Pillow's built-in font has no accented glyphs, so "Château" rendered as tofu. format_event_when → "Fri 19 Feb 2027, 16:00 - 20:00"; filename ticket-<event-slug>-<id8>.png.
  • GET /events/api/v1/ticket-card/{ticket_id} serves the same PNG (anonymous like /qr/); the email's "Ticket image" link points there now.
  • Email becomes multipart/mixed: text + HTML alternatives (URLs as links, no <img>) plus the card as a PNG attachment — inline at the end of the message in Gmail/Apple Mail/Thunderbird, an attachment card in Outlook/Proton, and it works offline at the door.

Sample card is attached on the PR conversation (rendered with demo's QR logo). 38 tests pass (card rendering, filename, multipart structure); black / ruff / prettier clean; mypy only reports the pre-existing crud.py / nostr_sync.py annotations.

config.json → 1.6.1-aio.10. Rebase note for #33: make_qr_png now lives in qr.py, otherwise upstream-shaped.

Deploy

Merge → tag v1.6.1-aio.10 → catalog entry → upgrade on demo → mail-tester re-run (expect the image-only rule gone).

🤖 Generated with Claude Code

https://claude.ai/code/session_01EYwoAkZZmXMMmaBp4WGUBo

## Why After #42 the ticket mail scored **8.4/10** on mail-tester; the last deduction was `HTML_IMAGE_ONLY_08` (1.8) — an HTML part whose only content of note is a remote `<img>`. Two more reasons to change how the QR travels: most clients block remote images until the reader opts in, and a bare QR saved from the mail says nothing about what it opens. ## What - **`qr.py`** (QR + logo helpers moved out of `views_api.py`) gains `render_ticket_card`: site title, event name, when/where, the branded QR, name on ticket, ticket id, door instruction. Laid out with **DejaVu Sans, bundled** under `static/fonts/` with its licence — Pillow's built-in font has no accented glyphs, so "Château" rendered as tofu. `format_event_when` → "Fri 19 Feb 2027, 16:00 - 20:00"; filename `ticket-<event-slug>-<id8>.png`. - **`GET /events/api/v1/ticket-card/{ticket_id}`** serves the same PNG (anonymous like `/qr/`); the email's "Ticket image" link points there now. - **Email** becomes `multipart/mixed`: text + HTML alternatives (URLs as links, **no `<img>`**) plus the card as a PNG attachment — inline at the end of the message in Gmail/Apple Mail/Thunderbird, an attachment card in Outlook/Proton, and it works offline at the door. Sample card is attached on the PR conversation (rendered with demo's QR logo). 38 tests pass (card rendering, filename, multipart structure); black / ruff / prettier clean; mypy only reports the pre-existing `crud.py` / `nostr_sync.py` annotations. `config.json` → `1.6.1-aio.10`. Rebase note for #33: `make_qr_png` now lives in `qr.py`, otherwise upstream-shaped. ## Deploy Merge → tag `v1.6.1-aio.10` → catalog entry → upgrade on demo → mail-tester re-run (expect the image-only rule gone). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01EYwoAkZZmXMMmaBp4WGUBo
Pillow's built-in default font has no accented glyphs, so any French
event name ("Château") renders as tofu. DejaVu Sans (Bitstream Vera
licence, included) covers Latin fully and is what the ticket card uses.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYwoAkZZmXMMmaBp4WGUBo
feat: attach a self-describing ticket card to the email (1.6.1-aio.10)
Some checks failed
lint.yml / feat: attach a self-describing ticket card to the email (1.6.1-aio.10) (pull_request) Failing after 0s
2f8a602bbd
The v1.6.1-aio.9 mail still scored 8.4/10 on mail-tester: the remaining
deduction was HTML_IMAGE_ONLY (1.8) — an HTML part whose only content of
note is a remote <img>. Remote images are also blocked by default in most
clients until the reader opts in, and a bare QR saved from that mail says
nothing about what it opens.

- New `qr.py` module (QR + logo helpers moved out of views_api) with
  `render_ticket_card`: site title, event name, when/where, the branded
  QR, name on ticket, ticket id and the door instruction, laid out with
  the bundled DejaVu Sans; `format_event_when` gives "Fri 19 Feb 2027,
  16:00 - 20:00"; filenames are `ticket-<event-slug>-<id8>.png`.
- `GET /events/api/v1/ticket-card/{ticket_id}` serves the same PNG
  (anonymous, like the QR endpoint); the email's "Ticket image" link
  now points there.
- The ticket email becomes multipart/mixed: text + HTML alternatives
  (URLs as links, no <img>) plus the card as a PNG attachment, which
  clients show inline at the end of the message and which works offline
  at the door.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYwoAkZZmXMMmaBp4WGUBo
padreug deleted branch feat/ticket-card-attachment 2026-09-08 14:53:06 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/events!43
No description provided.