<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Gareth Evans</title>
    <description>The latest articles on Forem by Gareth Evans (@agrath).</description>
    <link>https://forem.com/agrath</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3807422%2Fad5901f9-84b7-41b2-ada2-d7aa2e28f728.png</url>
      <title>Forem: Gareth Evans</title>
      <link>https://forem.com/agrath</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/agrath"/>
    <language>en</language>
    <item>
      <title>I built an email-to-URL service on Cloudflare Workers — here's what I learned about parsing email threads</title>
      <dc:creator>Gareth Evans</dc:creator>
      <pubDate>Thu, 05 Mar 2026 08:57:18 +0000</pubDate>
      <link>https://forem.com/agrath/i-built-an-email-to-url-service-on-cloudflare-workers-heres-what-i-learned-about-parsing-email-3heg</link>
      <guid>https://forem.com/agrath/i-built-an-email-to-url-service-on-cloudflare-workers-heres-what-i-learned-about-parsing-email-3heg</guid>
      <description>&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;Email threads are surprisingly hard to share outside email. Screenshots lose context, forwarding creates quote nesting hell, and copy-paste strips formatting.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://threadcrunch.io" rel="noopener noreferrer"&gt;ThreadCrunch&lt;/a&gt; — forward any email thread to &lt;code&gt;share@threadcrunch.io&lt;/code&gt; and get a clean, readable URL back in seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;p&gt;Everything runs on Cloudflare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Email Workers&lt;/strong&gt; — receive inbound email at custom addresses&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workers&lt;/strong&gt; — API + business logic (TypeScript)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;D1&lt;/strong&gt; — SQLite database&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pages&lt;/strong&gt; — Vue 3 + Tailwind frontend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total monthly infrastructure cost for a solo SaaS: basically zero until you hit scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hard part: parsing email threads
&lt;/h2&gt;

&lt;p&gt;Every email client formats forwarded threads differently:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Outlook&lt;/strong&gt; uses separator lines and inline header blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;From: Alice
Sent: Monday, March 3, 2026
To: Bob
Subject: Re: Project update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Gmail&lt;/strong&gt; uses "On {date}, {person} wrote:" followed by &lt;code&gt;&amp;gt;&lt;/code&gt; quoted lines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Webmail (Roundcube, etc.)&lt;/strong&gt; uses RFC 3676 &lt;code&gt;format=flowed&lt;/code&gt;, which joins soft-wrapped lines with trailing spaces. This completely destroys thread structure if you let your MIME parser decode it — I had to strip &lt;code&gt;format=flowed&lt;/code&gt; from the Content-Type header before parsing and handle space-stuffing manually.&lt;/p&gt;

&lt;p&gt;The fun edge cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Header fields that wrap across lines (long From/To addresses)&lt;/li&gt;
&lt;li&gt;Outlook messages containing Gmail-style quoted replies inside them&lt;/li&gt;
&lt;li&gt;Mixed clients in the same thread (someone replies from Outlook to a Gmail chain)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  No signup wall
&lt;/h2&gt;

&lt;p&gt;You don't have to sign up before forwarding. If you're not subscribed, the reply email includes a signup link and your threads get processed automatically once payment goes through.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI analysis
&lt;/h2&gt;

&lt;p&gt;There's also &lt;code&gt;process@threadcrunch.io&lt;/code&gt; which runs the thread through Claude Sonnet for analysis — tone, intent, power dynamics, action items, and a draft reply oriented to the person who forwarded.&lt;/p&gt;

&lt;p&gt;The key prompt design insight: doing per-message sequential analysis (tone, emotion, response timing, subtext) before synthesis produces significantly better output than asking for a flat "analyse this thread."&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer-friendly
&lt;/h2&gt;

&lt;p&gt;Every thread URL has &lt;code&gt;.md&lt;/code&gt; and &lt;code&gt;.json&lt;/code&gt; endpoints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;threadcrunch.io/t/{id}.json&lt;/code&gt; — structured JSON&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;threadcrunch.io/t/{id}.md&lt;/code&gt; — clean Markdown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful if you want to pipe threads into your own LLM tooling or documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Demo thread: &lt;a href="https://threadcrunch.io/t/5qyi25qv" rel="noopener noreferrer"&gt;threadcrunch.io/t/5qyi25qv&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;$5/month, threads auto-delete after 7 days. Would love feedback from the dev community.&lt;/p&gt;

</description>
      <category>webdev</category>
    </item>
  </channel>
</rss>
