design · inbound listing-site email · 2026-10-07 · Proposed, pending Fede
30 days to 2026-10-07, inbound prospect emails
Problem. When a renter replies through a listing site, we store the whole relay email as their message: logo, “New message from a renter”, “Reply on Zillow”, scam footer. The thread shows it and Clara’s model reads it. Keep only what the renter typed.
| Company | Inbound | Wrapped | Renter’s share of text |
|---|---|---|---|
| Camellia | 46 | 18 (39%) | 20% |
| Western Slope | 78 | 18 (23%) | 7% |
| Situs | no data (index gap) | ||
| Test properties | 126 | 25 (20%) | — |
61 of 61 wrapped messages were stored with noise. Camellia: AppFolio “New Lead” emails and website forms. Western Slope: Zillow (3 templates), Zumper, AppFolio relays. No Hotpads, Trulia, Rent. or RentCafe seen.
First lead emails have parsers. Zillow’s reply template has none, so the fallback stores the full body. Clara still answered correctly.
One extractor at ingestion outputs renterText (what the person typed) and keeps the full body as rawBody. One extractor per known relay, including the Zillow reply; unknown ones are cut at the first footer marker and raise an engineering alert. The thread shows renterText (“show original” available); so does Clara’s model. Backfill 90 days. Ships as a fix.
| Option | Trade-off | Effort |
|---|---|---|
| A. Parser per template + generic footer cutter recommended | Deterministic | 2 PRs |
| B. LLM extraction per email | Token cost and delay on every message | 1 PR + eval |
| C. Hide in the UI only | Model still reads the noise | 1 PR |
A Western Slope renter, one thread (names removed). “+ wrapper” = the relay text below.
| Time | Renter wrote | Stored text |
|---|---|---|
| Oct 4 15:47 | I would like to schedule a tour. | clean |
| Oct 7 00:43 | Hi yes when would you be available for a tour | + wrapper |
| Oct 7 00:47 | Could I do 1 | + wrapper |
| Oct 7 00:49 | Thanks you! | + wrapper |
| Oct 7 00:49 | See you tomorrow | + wrapper |
| Oct 7 19:11 | Hi are you steal good for one 1 today | + wrapper |
| Oct 7 19:12 | Are you meeting us there | + wrapper |
| Oct 7 19:13 | Or is it a self tour | + wrapper |
Wrapper, verbatim: “[Brand logo] New message from a renter / Regarding your listing at: <address> / Reply on Zillow / Some rental inquiries may be scams… / RENTER’S NAME <name> / RENTER’S MESSAGE <the words again>”
| Source | Rows | Company | Median stored / renter chars |
|---|---|---|---|
| AppFolio New Lead (Zillow inside) | 11 | Camellia | 610 / 99 |
| AppFolio New Lead (Apartments.com inside) | 3 | Camellia | 634 / 71 |
| Zillow “New message from a renter” | 9 | Western Slope | 424 / 24 |
| Zillow “says:” | 5 | Western Slope 2, test 3 | 3,808 / 116 |
| Zillow Rentals inquiry form | 3 | Western Slope | 467 / 63 |
| Website form | 4 | Camellia | 255 / 58 |
| Zumper | 1 | Western Slope | 134 / 31 |
| AppFolio relay of tenant message or document notice | 3 | Western Slope | 350 / 59 |
| Direct replies | 187 | all | 116 / 116 |
The stored text is built in the email ingestion step (agents/clara/lib/email/process-email-record.ts, about lines 915–946: zillowRenterMessage || strippedAgentBody || …). The Zillow relay matcher (parse-lead-source.ts L1210) only accepts the exact lines “New message”, “New application request” and “New tour request”. The lead parser looks for a “<Name> says:” line (L1241). Neither matches the reply template. The fallback stripQuotedReply only cuts “On … wrote:” chains.
Message rows have one content field: no html, no sender, no cleaned text. The UI renders content; the model history sends content verbatim.
| Template | Extractor |
|---|---|
| Zillow “says:” | covered |
| Zillow Rental Manager banner | covered first inquiry only |
| Zillow “New message from a renter” | missing |
| Apartments.com “says” | covered replies unverified |
| AppFolio lead relay | covered |
| TenantTurner, Apartments247, contact form | covered first leads only |
| Zumper, Rent., RentCafe, HotPads, Trulia, Realtor | none (HotPads and Trulia recognised for routing only) |
renterText (shown, sent to the model). content stays as the raw body (called rawBody in this doc). No migration of old rows; readers use renterText ?? content.email.unknown_relay_template engineering alert.renterText equal to the renter’s words (fixture test); 0 direct replies changed.~/agents/handoffs/qa-2026-10-06/relay-noise-stats-2026-10-07.md