From df76be1b87de14769a219ae0e6c99711edf993a1 Mon Sep 17 00:00:00 2001 From: Dries Augustyns Date: Mon, 20 Apr 2026 17:09:56 +0200 Subject: [PATCH] feat: Add accept/markdown to apps/landing --- apps/landing/src/content/pages.ts | 343 ++++++++++++++++++++++++++++++ apps/landing/src/middleware.ts | 34 +++ apps/landing/src/pages/api/md.ts | 24 +++ 3 files changed, 401 insertions(+) create mode 100644 apps/landing/src/content/pages.ts create mode 100644 apps/landing/src/middleware.ts create mode 100644 apps/landing/src/pages/api/md.ts diff --git a/apps/landing/src/content/pages.ts b/apps/landing/src/content/pages.ts new file mode 100644 index 0000000..41a51f8 --- /dev/null +++ b/apps/landing/src/content/pages.ts @@ -0,0 +1,343 @@ +export const MARKDOWN_PAGES: Record = { + index: `# Plunk — The Open-Source Email Platform + +Transactional emails, marketing campaigns, and workflow automation — in one platform. +Self-hostable, $0.001 per email, no contact limits. + +[Get started free](https://next-app.useplunk.com/auth/signup) | [Read the docs](https://docs.useplunk.com) + +--- + +## Key facts + +| Metric | Value | +|--------|-------| +| Price | $0.001 / email | +| GitHub stars | 5,000+ | +| Contacts | Unlimited, always free | +| Setup time | < 5 minutes | +| License | AGPL-3.0 | + +--- + +## Replace your email stack + +One tool in place of Resend, SendGrid, Mailchimp, Customer.io, and Mailgun. + +- [Plunk vs Resend](/vs/resend) +- [Plunk vs SendGrid](/vs/sendgrid) +- [Plunk vs Mailchimp](/vs/mailchimp) +- [Plunk vs Customer.io](/vs/customerio) +- [Plunk vs Mailgun](/vs/mailgun) + +--- + +## Why Plunk + +### Setup — < 5 min +Most email platforms take days to configure. Plunk is running in under five minutes — domain, DKIM, and first send included. + +### Pricing — 0 limits +Other platforms charge more as your list grows. Plunk stores unlimited contacts for free and bills only on send. + +### Ownership — AGPL-3.0 +Closed-source platforms own your stack. Plunk is fully inspectable, forkable, and self-hostable on your own infra. + +--- + +## Features + +### Workflow Automation +Visual builder for complex email sequences with triggers, delays, and conditional logic. No code required. + +### Dynamic Segments +Real-time audience segmentation based on contact data and behavior. + +### Campaign Management +Broadcast emails with scheduling and performance tracking. + +### Analytics +Detailed metrics on opens, clicks, bounces, and conversions across campaigns. + +### Inbound Email +Receive and process incoming emails with webhook notifications. + +### Custom Domains +Brand consistency with DKIM authentication and custom sending domains. + +--- + +## Data model + +Every interaction flows into a single contact record — transactional, campaign, and workflow events unified in one source of truth. + +- **Transactional** — Receipts, password resets, event-driven sends +- **Campaigns** — Newsletters, product launches, announcements +- **Workflows** — Onboarding sequences, drip campaigns + +--- + +## Open source + +- **License**: AGPL-3.0 +- **Hosting**: EU-hosted, GDPR compliant +- **Deployment**: Self-hostable via Docker Compose +- **Community**: 5,000+ GitHub stars + +[View on GitHub](https://github.com/useplunk/plunk) + +--- + +## Pricing comparison + +**Plunk: $0.001 / email** + +| Provider | Price / email | +|----------|--------------| +| Plunk | $0.001 | +| Mailgun | $0.003 | +| SendGrid | $0.002 | +| Mailchimp | $0.004 | + +*Based on plans matching Plunk at 10,000 emails per month.* + +[Full pricing details](/pricing) + +--- + +## Testimonials + +> "Transparent and intuitive UI, extremely easy setup & automation and great support." +> — Artur Czemiel, Founder at GraphQL Editor + +> "I've been using Plunk for building & sending out marketing emails and genuinely love it!" +> — Joe Ashwell, Founder at UnwindHR + +> "I loved the ease of use, beautiful UI and great UX. Everything simply works." +> — Alisson Leal, Founder at Brapi + +> "Clean design, easy to understand, fair pricing." +> — Pierre Jacquel, Founder at Landingly + +> "Simple to use, efficient and no regrets!" +> — Noah Di Gesu, Founder at Smoothey + +> "Lots of care put into Plunk" +> — Jonni Lundy, Founding Operations Manager at Resend + +--- + +## FAQ + +**How is Plunk different from other email automation tools?** +Plunk is built for SaaS businesses, indie hackers, and developers. Create complex automated email flows and trigger them from anywhere through a single API call. + +**Can I use Plunk for transactional emails?** +Yes. Plunk handles transactional emails — sign-ups, cancellations, plan changes — alongside marketing emails in the same platform. + +**Can I use Plunk for newsletters?** +Yes. Plunk lets you send newsletters and broadcast emails to your full list or any segment. + +**What programming languages does Plunk support?** +Any language capable of HTTP requests. Plunk provides a REST API plus SDKs for Node.js, Python, and more. + +**How much does Plunk cost?** +Free plan includes 1,000 emails/month. Paid plan is $0.001 per email with no contact limits. + +--- + +Start sending in 5 minutes. Free plan available. No contact limits, no surprises. + +[Create free account](https://next-app.useplunk.com/auth/signup) | [Read the docs](https://docs.useplunk.com) +`, + + pricing: `# Plunk Pricing — Simple, Transparent + +Free plan: 1,000 emails/month. Paid plan: $0.001/email. Unlimited contacts, no hidden fees. + +--- + +## Plans + +### Free forever + +**1,000 emails / month** — No credit card required + +Includes: +- Transactional emails +- Workflow automation +- Campaign broadcasts +- Custom domains +- Click & open tracking +- Unlimited contacts +- Plunk branding on emails (removed on paid) + +[Start for free](https://next-app.useplunk.com/auth/signup) + +--- + +### Pay as you grow + +**$0.001 / email** — No base fee + +Includes everything in Free, plus: +- No Plunk branding +- Monthly spend cap +- Unlimited emails + +[Get started](https://next-app.useplunk.com/auth/signup) + +--- + +## Every feature, every plan + +No feature tiers, no add-ons, no surprises. + +| Feature | Description | +|---------|-------------| +| Transactional emails | API and SMTP delivery for receipts, password resets, and event-driven email. | +| Workflow automation | Event-triggered sequences with delays, conditions, and branching logic. | +| Campaign broadcasts | Send newsletters and announcements to your full list or a targeted segment. | +| Unlimited contacts | Store as many contacts as you need. Growing your list never costs more. | +| Full API access | REST API with SDKs for Node.js, Python, and more. | +| Custom domains | Send from your own domain with DKIM, SPF, and DMARC set up automatically. | +| Audience segmentation | Dynamic segments built on behavior, attributes, and engagement data. | +| Analytics & tracking | Opens, clicks, bounces, and unsubscribes. Real data, no guessing. | +| Open source | AGPL-3.0 licensed. Inspect the code, self-host it, or contribute. | + +--- + +## Self-host for free + +Run Plunk on your own infrastructure — full data ownership, no per-email costs, GDPR compliance by default. +Deploy with Docker Compose in minutes. + +[View on GitHub](https://github.com/useplunk/plunk) + +--- + +Start sending in 5 minutes. Free plan, no credit card required. + +[Create free account](https://next-app.useplunk.com/auth/signup) | [Self-host for free](https://github.com/useplunk/plunk) +`, + + 'features/workflows': `# Workflow Automation — Plunk + +Visual builder for complex email sequences with triggers, delays, and conditional logic. No code required. + +[Get started free](https://next-app.useplunk.com/auth/signup) | [Documentation](https://docs.useplunk.com) + +--- + +## What are workflows? + +Workflows are automated email sequences that trigger based on events in your application. Define who receives emails, when they receive them, and what conditions must be met — all without writing code. + +## Key capabilities + +- **Event-triggered**: Start workflows from any API event +- **Delays**: Wait minutes, hours, or days between steps +- **Conditional branching**: Branch paths based on contact data or behavior +- **Visual builder**: Drag-and-drop interface, no code required +- **Unlimited steps**: As complex as your use case demands + +## Use cases + +- **Onboarding sequences**: Welcome new users and guide them to activation +- **Drip campaigns**: Nurture leads over time with educational content +- **Re-engagement**: Win back inactive contacts automatically +- **Lifecycle emails**: Upgrades, renewals, cancellations + +[Back to features](/features) | [Pricing](/pricing) +`, + + 'features/segments': `# Dynamic Segments — Plunk + +Real-time audience segmentation based on contact data and behavior. + +[Get started free](https://next-app.useplunk.com/auth/signup) + +--- + +## What are segments? + +Segments are dynamic groups of contacts that update automatically as contact data changes. Target campaigns and workflows to exactly the right audience without manual list management. + +## Capabilities + +- **Attribute-based**: Filter by any contact property +- **Behavior-based**: Segment by email opens, clicks, and engagement +- **Real-time**: Segments update instantly as contact data changes +- **Combinable**: AND/OR logic for complex targeting +- **Unlimited contacts**: No per-segment contact limits + +[Back to features](/features) | [Pricing](/pricing) +`, + + 'features/inbound-email': `# Inbound Email — Plunk + +Receive and process incoming emails with webhook notifications. + +[Get started free](https://next-app.useplunk.com/auth/signup) + +--- + +## What is inbound email? + +Inbound email lets your application receive emails sent to your Plunk domain. When a message arrives, Plunk parses it and delivers the content to your webhook endpoint in real time. + +## Capabilities + +- **Webhook delivery**: Parsed email payload posted to your endpoint +- **Attachment handling**: Access attachments programmatically +- **Custom addresses**: Route different addresses to different webhooks +- **Reply detection**: Track email threads automatically + +[Back to features](/features) | [Pricing](/pricing) +`, + + 'features/email-editor': `# Email Editor — Plunk + +Design beautiful emails with a drag-and-drop builder or write in Markdown. + +[Get started free](https://next-app.useplunk.com/auth/signup) + +--- + +## What is the email editor? + +Plunk's email editor lets you build professional emails without writing HTML. Choose from the visual drag-and-drop builder or write in Markdown — both export to responsive HTML email. + +## Capabilities + +- **Drag-and-drop builder**: Compose layouts with blocks and columns +- **Markdown mode**: Write in plain text, render as rich email +- **Responsive**: Emails adapt to any screen size automatically +- **Preview**: See how your email looks on desktop and mobile +- **Reusable templates**: Save and reuse your designs + +[Back to features](/features) | [Pricing](/pricing) +`, + + 'features/smtp': `# SMTP — Plunk + +Send emails through Plunk using standard SMTP — no API changes required. + +[Get started free](https://next-app.useplunk.com/auth/signup) + +--- + +## SMTP access + +Plunk provides SMTP credentials so you can send emails from any application or framework that supports standard SMTP. Drop in your Plunk credentials and start sending immediately — no code changes needed beyond configuration. + +## Details + +- **Host**: SMTP endpoint provided in your dashboard +- **Port**: 587 (TLS) or 465 (SSL) +- **Authentication**: Username and password from your Plunk project +- **Compatible with**: Any language, framework, or tool that supports SMTP + +[Back to features](/features) | [Pricing](/pricing) | [Documentation](https://docs.useplunk.com) +`, +}; diff --git a/apps/landing/src/middleware.ts b/apps/landing/src/middleware.ts new file mode 100644 index 0000000..1e1d072 --- /dev/null +++ b/apps/landing/src/middleware.ts @@ -0,0 +1,34 @@ +import { NextResponse } from 'next/server'; +import type { NextRequest } from 'next/server'; + +function acceptsMarkdown(accept: string): boolean { + for (const part of accept.split(',')) { + const segments = part.trim().split(';'); + if (segments[0]?.trim().toLowerCase() !== 'text/markdown') continue; + const qParam = segments.slice(1).find(s => s.trim().startsWith('q=')); + const q = qParam ? parseFloat((qParam.split('=')[1]) ?? '1') : 1; + return !isNaN(q) && q > 0; + } + return false; +} + +export function middleware(request: NextRequest) { + const accept = request.headers.get('accept') ?? ''; + const { pathname } = request.nextUrl; + + if (acceptsMarkdown(accept)) { + const headers = new Headers(request.headers); + headers.set('x-md-path', pathname); + const response = NextResponse.rewrite(new URL('/api/md', request.url), { request: { headers } }); + response.headers.set('Vary', 'Accept'); + return response; + } + + const response = NextResponse.next(); + response.headers.set('Vary', 'Accept'); + return response; +} + +export const config = { + matcher: ['/((?!api|_next|favicon\\.ico|assets|.*\\.(?:png|jpg|jpeg|gif|svg|ico|webp|woff|woff2|ttf|css|js)).*)',], +}; diff --git a/apps/landing/src/pages/api/md.ts b/apps/landing/src/pages/api/md.ts new file mode 100644 index 0000000..76f6faf --- /dev/null +++ b/apps/landing/src/pages/api/md.ts @@ -0,0 +1,24 @@ +import type { NextApiRequest, NextApiResponse } from 'next'; + +import { MARKDOWN_PAGES } from '../../content/pages'; + +export default function handler(req: NextApiRequest, res: NextApiResponse) { + const pathname = req.headers['x-md-path']; + if (typeof pathname !== 'string') { + res.status(406).end(); + return; + } + + const slug = pathname.replace(/^\/+|\/+$/g, '') || 'index'; + + res.setHeader('Vary', 'Accept'); + + const content = MARKDOWN_PAGES[slug]; + if (!content) { + res.status(406).end(); + return; + } + + res.setHeader('Content-Type', 'text/markdown; charset=utf-8'); + res.status(200).send(content); +}