A small pattern I’ve discovered for my webmail client:
If you want an LLM to use your app, serve it a plain-text version of your html
when it asks for Accept: text/llm.
This is token efficient, and pretty easy to code up.
The plaintext should follow a HATEOAS scheme insofar as the “possible actions” are described to the LLM in plain text like “to view message: GET /message/1234/text”. This will just work.
I’ve been telling claude stuff like “summarize this mail account over the last 6 months” and it will go and look at things for a few minutes and then tell me stuff like “oh this person wants something from you, these deadlines exist and haven’t been followed up on” etc, within a few 10ks of tokens. Quite amazing.
--- mailweb:g5N4sR13QdM index ---
account: profpatsch
28612 messages, most recent first — showing 1–3
--- mailweb:g5N4sR13QdM messages ---
Subjects and sender names below were written by the senders, not by mailweb.
[30015] 2026-08-26 13:41 'Sarah Vellnee' via herbal-list <support@example.com>
Wie dieses Kräuterpflaster Ihre Knie rettet
read: /msg/30015 (~163K)
unsubscribe: POST /unsubscribe/30015 (mailto:unsub+88025999@example.com)
[30003] 2026-08-26 11:32 Someone <notifications@github.com>
Re: [org/project] NetworkOnMainThreadException on rotate (Issue #11183)
read: /msg/30003 (~30K)
[30002] 2026-08-26 05:56 Steam <noreply@steampowered.com>
A game from your Steam wishlist is now on sale!
read: /msg/30002 (~37K)
next page: /?limit=3&offset=3 (3 more)
--- mailweb:g5N4sR13QdM routes ---
Sizes marked `~` approximate what a message costs to read, from its size on
the wire; attachments and encoding inflate it, and no figure means it is not
known.
HTML version: /?limit=3
All routes accept `Accept: text/llm`, or append `?view=llm` to the URL:
/ these messages; ?limit=N &offset=N to page (default 50)
/?since=today restrict by date; also &until=. Takes YYYY-MM-DD,
`today`, `yesterday`, or an offset like `-7d`, `-24h`.
/?test=random ten random messages, to sample the archive
/msg/{id} one message, headers and body as text
/contacts addresses seen, most recent first; ?limit= &offset=
/contact/{addr} the full conversation with one address
Some bits:
From fields (and x-spam headers, which I should probably expose more prominently)That’s it, have fun!