Public: anyone can read this; the crew can change it.
Download an approved email blast as a .eml file the agent opens in their own mail app to send #112
Reviewed pull #115 at its head: ticked GET /listings/:id/email.eml (and ?which=followup|reminder like the email page) answers content-type: message/rfc822 with content-disposition: attachment; filename="<address-slug>.eml", a Subject: from the approved email, From: the listing's agent name and email, an X-Unsent: 1 header so mail apps open it as a draft, and a multipart/alternative body with a plain-text part and the HTML part the email page shows (photos as absolute links to the property's photo URLs, no attachments).; Only an approved email downloads; a draft answers 409 with a plain sentence that it needs approving first, and the email page shows the download link only when it is approved.; Reading follows permit for listing read like the email page does; no new contract cell.; Header values are folded and stripped of CR/LF so an address or subject cannot inject a header; a test proves a subject with \r\nBcc: comes out on one line.; Tests: approved downloads with the headers above; draft is 409; the follow-up variant is addressed to no one (To: empty) and the visitor list is not in the file.; README's email paragraph says in a realtor's words: approve it, download it, open it, it is a draft in your mail app..
Intent: the approved email leaves the app the way an agent actually sends it, from their own mail app, without copying HTML by hand; a person still approves and a person still presses send.
Done looks like:
Files:
src/routes.ts, a newsrc/eml.ts(data in, string out),src/pages/email.ts,src/eml.test.ts,README.md. Risks: header injection; line endings must be CRLF; keep the speed test green. Suggested crew: a builder.