<?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>DEV Community: 강상권</title>
    <description>The latest articles on DEV Community by 강상권 (@sangkwun).</description>
    <link>https://dev.to/sangkwun</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%2F3803438%2F82f93541-3816-499d-afdc-685749015c1f.png</url>
      <title>DEV Community: 강상권</title>
      <link>https://dev.to/sangkwun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sangkwun"/>
    <language>en</language>
    <item>
      <title>I open-sourced the Notion Email rendering engine from my SaaS</title>
      <dc:creator>강상권</dc:creator>
      <pubDate>Sun, 05 Apr 2026 13:21:11 +0000</pubDate>
      <link>https://dev.to/sangkwun/i-open-sourced-the-notion-email-rendering-engine-from-my-saas-4ebk</link>
      <guid>https://dev.to/sangkwun/i-open-sourced-the-notion-email-rendering-engine-from-my-saas-4ebk</guid>
      <description>&lt;p&gt;I've been running &lt;a href="https://notionto.email" rel="noopener noreferrer"&gt;notionto.email&lt;/a&gt;, a service that&lt;br&gt;
sends Notion pages as emails. The hardest part wasn't the Notion API or email&lt;br&gt;
delivery. It was the rendering layer.&lt;/p&gt;

&lt;p&gt;So I extracted it and open-sourced it: &lt;strong&gt;&lt;a href="https://github.com/Sangkwun/notion-to-email" rel="noopener noreferrer"&gt;notion-to-email&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;notion-to-email&lt;/code&gt; is a TypeScript library that turns any Notion page into&lt;br&gt;
email-compatible HTML, ready to pass to SES, SendGrid, Resend, or Nodemailer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;renderFromNotion&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notion-to-email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderFromNotion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;pageId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-page-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-notion-token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="c1"&gt;// Pass html to SES, SendGrid, Nodemailer, Resend, etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The rendering problem
&lt;/h2&gt;

&lt;p&gt;Email HTML is notoriously finicky. No Flexbox. No Grid. Table-based layouts,&lt;br&gt;
inline styles, and every client renders things slightly differently.&lt;/p&gt;

&lt;p&gt;Notion's private images also use short-lived signed URLs, so you need to&lt;br&gt;
re-host them before sending or they'll be broken by the time someone opens&lt;br&gt;
the email.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;notion-to-email @notionhq/client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's supported
&lt;/h2&gt;

&lt;p&gt;20+ block types, all rendered to table-based email HTML:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paragraphs, Headings H1–H4&lt;/li&gt;
&lt;li&gt;Bulleted &amp;amp; Numbered Lists&lt;/li&gt;
&lt;li&gt;To-Do, Toggle, Quote, Callout&lt;/li&gt;
&lt;li&gt;Code blocks, Equations (image fallback)&lt;/li&gt;
&lt;li&gt;Tables, Column layouts&lt;/li&gt;
&lt;li&gt;Images, YouTube thumbnails, File links, Bookmarks&lt;/li&gt;
&lt;li&gt;Synced blocks, Child pages/databases, Link to page, Table of Contents&lt;/li&gt;
&lt;li&gt;Rich text: bold, italic, strikethrough, inline code, colors, links, mentions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;renderFromNotion&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;pageId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-page-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;your-token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Notion private images expire quickly. Re-host them before sending&lt;/span&gt;
    &lt;span class="c1"&gt;// so they're still visible when recipients open the email.&lt;/span&gt;
    &lt;span class="c1"&gt;// `context` contains { blockId, blockType, pageId, isPublicPage, usage }.&lt;/span&gt;
    &lt;span class="c1"&gt;// usage: 'image' | 'cover' | 'icon' | 'file'&lt;/span&gt;
    &lt;span class="na"&gt;resolveImageUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="s2"&gt;`https://your-cdn.com/proxy?url=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nf"&gt;encodeURIComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// Show a "View in Notion" button at the top of the email&lt;/span&gt;
    &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;showNotionButton&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="c1"&gt;// Append a custom footer (raw HTML)&lt;/span&gt;
    &lt;span class="na"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;p&amp;gt;Sent via My App&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="c1"&gt;// 'placeholder' renders a visible fallback for unsupported blocks&lt;/span&gt;
    &lt;span class="c1"&gt;// instead of silently dropping them&lt;/span&gt;
    &lt;span class="na"&gt;onUnsupportedBlock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;placeholder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CLI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx notion-to-email &amp;lt;page-id&amp;gt; &lt;span class="nt"&gt;--token&lt;/span&gt; secret_xxx
npx notion-to-email &amp;lt;page-id&amp;gt; &lt;span class="nt"&gt;-o&lt;/span&gt; email.html
npx notion-to-email https://notion.so/My-Page-abc123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub: &lt;a href="https://github.com/Sangkwun/notion-to-email" rel="noopener noreferrer"&gt;https://github.com/Sangkwun/notion-to-email&lt;/a&gt;&lt;br&gt;
npm: &lt;a href="https://www.npmjs.com/package/notion-to-email" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/notion-to-email&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MIT licensed. PRs and issues are always welcome.&lt;/p&gt;

</description>
      <category>notion</category>
      <category>typescript</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built a tool that turns RSS, YouTube, and Reddit into a single daily briefing</title>
      <dc:creator>강상권</dc:creator>
      <pubDate>Tue, 03 Mar 2026 08:44:08 +0000</pubDate>
      <link>https://dev.to/sangkwun/i-built-a-tool-that-turns-rss-youtube-and-reddit-into-a-single-daily-briefing-1nci</link>
      <guid>https://dev.to/sangkwun/i-built-a-tool-that-turns-rss-youtube-and-reddit-into-a-single-daily-briefing-1nci</guid>
      <description>&lt;p&gt;Every morning I used to open the same 15 tabs. Tech blogs, YouTube channels, a couple of subreddits, some newsletters I'd subscribed to months ago and barely read.&lt;/p&gt;

&lt;p&gt;It took about 40 minutes. Most of that time was spent skimming stuff I didn't need.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://daige.st/" rel="noopener noreferrer"&gt;Daigest&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;You connect your sources (RSS feeds, YouTube channels, Reddit subs, whatever you follow) and Daigest generates a summarized briefing. Daily or weekly, your call.&lt;/p&gt;

&lt;p&gt;The briefing is a single page, readable in about 3 minutes. Want to share it with your team? Send them the link.&lt;/p&gt;

&lt;p&gt;That's pretty much it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;I tried RSS readers first, but my unread count just kept growing. Google Alerts sent me keyword matches with zero context. I subscribed to 30+ newsletters and actually read maybe 3. Tried just Googling stuff every morning, which works, but gets old fast.&lt;/p&gt;

&lt;p&gt;None of these solved what I actually wanted: a short summary of what happened across my sources. Not another inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Pick your sources (RSS, YouTube, Reddit, and more)&lt;/li&gt;
&lt;li&gt;Daigest pulls new content and summarizes it with AI&lt;/li&gt;
&lt;li&gt;You get a briefing, one page, readable in minutes&lt;/li&gt;
&lt;li&gt;Share via link if your team needs it too&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tech stack
&lt;/h2&gt;

&lt;p&gt;For anyone curious about what's under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: Next.js (App Router)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Supabase (Postgres + Auth + Edge Functions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI&lt;/strong&gt;: Multiple LLMs for summarization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting&lt;/strong&gt;: Vercel&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I learned building this
&lt;/h2&gt;

&lt;p&gt;Summarization quality was the hardest part. Early versions either missed important stuff or included too much noise. Took a lot of tweaking to get it right. Turns out prompt engineering matters way more than which model you pick.&lt;/p&gt;

&lt;p&gt;The other surprise: people use this differently than I expected. I built it for myself (a developer who reads too many blogs), but most active users are actually sharing team briefings. PMs sending weekly industry updates, that kind of thing. Didn't see that coming.&lt;/p&gt;

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

&lt;p&gt;It's free to start: &lt;a href="https://daige.st/" rel="noopener noreferrer"&gt;daige.st&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it, I'm curious what sources you'd connect first. Happy to hear what's missing too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://x.com/daigestHQ" rel="noopener noreferrer"&gt;X (@daigestHQ)&lt;/a&gt; if you want to say hi.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>ai</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
