chore: Replace references to deprecated services

This commit is contained in:
Dries Augustyns
2025-12-31 15:08:26 +01:00
parent 289c633189
commit 7648f6e1eb
51 changed files with 163 additions and 183 deletions
+4 -4
View File
@@ -27,10 +27,10 @@ WIKI_URI=http://localhost:1000
# NEXT_PUBLIC_* variables are used for client-side code and sitemap generation # NEXT_PUBLIC_* variables are used for client-side code and sitemap generation
# Use placeholder URLs that will be replaced at Docker container runtime # Use placeholder URLs that will be replaced at Docker container runtime
NEXT_PUBLIC_API_URI=https://api.useplunk.com NEXT_PUBLIC_API_URI=https://next-api.useplunk.com
NEXT_PUBLIC_DASHBOARD_URI=https://app.useplunk.com NEXT_PUBLIC_DASHBOARD_URI=https://next-app.useplunk.com
NEXT_PUBLIC_LANDING_URI=https://www.useplunk.com NEXT_PUBLIC_LANDING_URI=https://next.useplunk.com
NEXT_PUBLIC_WIKI_URI=https://docs.useplunk.com NEXT_PUBLIC_WIKI_URI=https://next-wiki.useplunk.com
# Set to 'true' if using HTTPS in production (behind a reverse proxy/load balancer) # Set to 'true' if using HTTPS in production (behind a reverse proxy/load balancer)
# This affects how application URIs are auto-generated from domain names # This affects how application URIs are auto-generated from domain names
+3 -3
View File
@@ -67,9 +67,9 @@ to run them separately (e.g., for debugging), use `dev:server` and `dev:worker`
- HTTP API endpoints for the platform - HTTP API endpoints for the platform
- Background cron jobs (workflow processor, domain verification) - Background cron jobs (workflow processor, domain verification)
- **Worker process** (separate): BullMQ worker for processing email, campaign, and workflow queues - **Worker process** (separate): BullMQ worker for processing email, campaign, and workflow queues
- **web**: Next.js app (Pages Router) - Main platform (app.useplunk.com) - **web**: Next.js app (Pages Router) - Main platform (next-app.useplunk.com)
- **landing**: Next.js app (Pages Router) - Marketing site (www.useplunk.com) - **landing**: Next.js app (Pages Router) - Marketing site (next.useplunk.com)
- **wiki**: Next.js app - Documentation site (docs.useplunk.com) - **wiki**: Next.js app - Documentation site (next-wiki.useplunk.com)
### Background Job Architecture ### Background Job Architecture
+3 -3
View File
@@ -10,8 +10,8 @@ Plunk V2 is built as a modern Turborepo monorepo with the following structure:
- **api**: Express.js API server with background worker process (BullMQ) - **api**: Express.js API server with background worker process (BullMQ)
- **web**: Next.js dashboard application (app.useplunk.com) - **web**: Next.js dashboard application (app.useplunk.com)
- **landing**: Next.js marketing site (www.useplunk.com) - **landing**: Next.js marketing site (next.useplunk.com)
- **wiki**: Next.js documentation site (docs.useplunk.com) - **wiki**: Next.js documentation site (next-wiki.useplunk.com)
### Shared Packages (`packages/`) ### Shared Packages (`packages/`)
@@ -135,7 +135,7 @@ between groups.
## Need Help? ## Need Help?
- Check the [documentation](https://docs.useplunk.com) - Check the [documentation](https://next-wiki.useplunk.com)
- Open an issue for bugs or feature requests - Open an issue for bugs or feature requests
- Join our community discussions - Join our community discussions
+1 -1
View File
@@ -1,5 +1,5 @@
/** @type {import('next-sitemap').IConfig} */ /** @type {import('next-sitemap').IConfig} */
module.exports = { module.exports = {
siteUrl: process.env.NEXT_PUBLIC_LANDING_URI || 'https://www.useplunk.com', siteUrl: process.env.NEXT_PUBLIC_LANDING_URI || 'https://next.useplunk.com',
generateRobotsTxt: true, generateRobotsTxt: true,
}; };
@@ -25,7 +25,7 @@ export function GuideLayout({
readTime, readTime,
children, children,
canonical, canonical,
ogImage = 'https://www.useplunk.com/assets/card.png', ogImage = 'https://next.useplunk.com/assets/card.png',
}: GuideLayoutProps) { }: GuideLayoutProps) {
const [headings, setHeadings] = useState<{id: string; text: string; level: number}[]>([]); const [headings, setHeadings] = useState<{id: string; text: string; level: number}[]>([]);
const [activeId, setActiveId] = useState<string>(''); const [activeId, setActiveId] = useState<string>('');
@@ -74,8 +74,8 @@ export function GuideLayout({
// Generate breadcrumb items // Generate breadcrumb items
const breadcrumbItems = [ const breadcrumbItems = [
{position: 1, name: 'Home', item: 'https://www.useplunk.com'}, {position: 1, name: 'Home', item: 'https://next.useplunk.com'},
{position: 2, name: 'Guides', item: 'https://www.useplunk.com/guides'}, {position: 2, name: 'Guides', item: 'https://next.useplunk.com/guides'},
{position: 3, name: title, item: canonical || ''}, {position: 3, name: title, item: canonical || ''},
]; ];
+1 -1
View File
@@ -63,7 +63,7 @@ export default function WithProviders(props: AppProps) {
title: 'Plunk | The Open-Source Email Platform', title: 'Plunk | The Open-Source Email Platform',
description: description:
'Open-source email automation platform with workflows, segments, and developer API. Scale from 0 to millions of emails at $0.001 per email. Self-hostable and privacy-first.', 'Open-source email automation platform with workflows, segments, and developer API. Scale from 0 to millions of emails at $0.001 per email. Self-hostable and privacy-first.',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk'}],
}} }}
additionalMetaTags={[{property: 'title', content: 'Plunk | The Open-Source Email Platform'}]} additionalMetaTags={[{property: 'title', content: 'Plunk | The Open-Source Email Platform'}]}
/> />
@@ -10,7 +10,7 @@ export default function EmailAPIGuide() {
description="Complete guide to email APIs: how they work, implementation examples, best practices, and choosing the right solution for your application." description="Complete guide to email APIs: how they work, implementation examples, best practices, and choosing the right solution for your application."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="12 min" readTime="12 min"
canonical="https://www.useplunk.com/guides/email-api-guide" canonical="https://next.useplunk.com/guides/email-api-guide"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -132,7 +132,7 @@ export default function EmailAPIGuide() {
language="javascript" language="javascript"
title="Node.js Example" title="Node.js Example"
code={`// Using fetch (Node.js 18+ or with node-fetch) code={`// Using fetch (Node.js 18+ or with node-fetch)
const response = await fetch('https://api.useplunk.com/v1/send', { const response = await fetch('https://next-api.useplunk.com/v1/send', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@@ -167,7 +167,7 @@ if (response.ok) {
code={`import requests code={`import requests
response = requests.post( response = requests.post(
'https://api.useplunk.com/v1/send', 'https://next-api.useplunk.com/v1/send',
headers={ headers={
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_API_KEY' 'Authorization': 'Bearer YOUR_API_KEY'
@@ -195,7 +195,7 @@ else:
language="php" language="php"
title="PHP Example" title="PHP Example"
code={`<?php code={`<?php
$ch = curl_init('https://api.useplunk.com/v1/send'); $ch = curl_init('https://next-api.useplunk.com/v1/send');
curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
@@ -235,7 +235,7 @@ if ($httpCode === 200) {
code={`require 'net/http' code={`require 'net/http'
require 'json' require 'json'
uri = URI('https://api.useplunk.com/v1/send') uri = URI('https://next-api.useplunk.com/v1/send')
http = Net::HTTP.new(uri.host, uri.port) http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true http.use_ssl = true
@@ -295,7 +295,7 @@ func main() {
jsonData, _ := json.Marshal(email) jsonData, _ := json.Marshal(email)
req, _ := http.NewRequest("POST", "https://api.useplunk.com/v1/send", bytes.NewBuffer(jsonData)) req, _ := http.NewRequest("POST", "https://next-api.useplunk.com/v1/send", bytes.NewBuffer(jsonData))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
@@ -10,7 +10,7 @@ export default function EmailBounceRate() {
description="Understand email bounce rates, the difference between hard and soft bounces, and proven strategies to reduce bounces and protect your sender reputation." description="Understand email bounce rates, the difference between hard and soft bounces, and proven strategies to reduce bounces and protect your sender reputation."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="9 min" readTime="9 min"
canonical="https://www.useplunk.com/guides/email-bounce-rate" canonical="https://next.useplunk.com/guides/email-bounce-rate"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -10,7 +10,7 @@ export default function EmailClickThroughRate() {
description="Learn what affects email click-through rates, industry benchmarks, and proven tactics to optimize CTAs and boost engagement." description="Learn what affects email click-through rates, industry benchmarks, and proven tactics to optimize CTAs and boost engagement."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="10 min" readTime="10 min"
canonical="https://www.useplunk.com/guides/email-click-through-rate" canonical="https://next.useplunk.com/guides/email-click-through-rate"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -9,7 +9,7 @@ export default function EmailDeliverability() {
description="Learn proven strategies to improve email deliverability, avoid spam filters, and maximize inbox placement rates. Complete guide with best practices." description="Learn proven strategies to improve email deliverability, avoid spam filters, and maximize inbox placement rates. Complete guide with best practices."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="12 min" readTime="12 min"
canonical="https://www.useplunk.com/guides/email-deliverability" canonical="https://next.useplunk.com/guides/email-deliverability"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -306,9 +306,7 @@ export default function EmailDeliverability() {
{/* Monitoring */} {/* Monitoring */}
<section id="monitoring" className="mb-12"> <section id="monitoring" className="mb-12">
<h2 className="text-3xl font-bold text-neutral-900 mb-6">Monitoring Email Deliverability</h2> <h2 className="text-3xl font-bold text-neutral-900 mb-6">Monitoring Email Deliverability</h2>
<p className="text-neutral-700 leading-relaxed mb-6"> <p className="text-neutral-700 leading-relaxed mb-6">Track these metrics to stay on top of deliverability:</p>
Track these metrics to stay on top of deliverability:
</p>
<div className="grid gap-6 md:grid-cols-2"> <div className="grid gap-6 md:grid-cols-2">
<div className="rounded-xl border border-neutral-200 bg-white p-6"> <div className="rounded-xl border border-neutral-200 bg-white p-6">
@@ -9,7 +9,7 @@ export default function EmailMarketingBestPractices() {
description="Master email marketing with proven best practices for content, design, timing, deliverability, and compliance. Comprehensive guide for 2025." description="Master email marketing with proven best practices for content, design, timing, deliverability, and compliance. Comprehensive guide for 2025."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="15 min" readTime="15 min"
canonical="https://www.useplunk.com/guides/email-marketing-best-practices" canonical="https://next.useplunk.com/guides/email-marketing-best-practices"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -10,7 +10,7 @@ export default function EmailOpenRate() {
description="Learn what affects email open rates, industry benchmarks, and proven tactics to improve opens. Complete guide with actionable tips." description="Learn what affects email open rates, industry benchmarks, and proven tactics to improve opens. Complete guide with actionable tips."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="10 min" readTime="10 min"
canonical="https://www.useplunk.com/guides/email-open-rate" canonical="https://next.useplunk.com/guides/email-open-rate"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -10,7 +10,7 @@ export default function EmailSenderReputation() {
description="Learn how sender reputation works, what affects it, and proven strategies to build and maintain a positive reputation for maximum deliverability." description="Learn how sender reputation works, what affects it, and proven strategies to build and maintain a positive reputation for maximum deliverability."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="11 min" readTime="11 min"
canonical="https://www.useplunk.com/guides/email-sender-reputation" canonical="https://next.useplunk.com/guides/email-sender-reputation"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
+3 -3
View File
@@ -103,13 +103,13 @@ export default function GuidesIndex() {
<NextSeo <NextSeo
title="Email Marketing & Deliverability Guides | Plunk" title="Email Marketing & Deliverability Guides | Plunk"
description="Learn email best practices, authentication (DKIM, SPF, DMARC), deliverability optimization, and more. Free guides from Plunk." description="Learn email best practices, authentication (DKIM, SPF, DMARC), deliverability optimization, and more. Free guides from Plunk."
canonical="https://www.useplunk.com/guides" canonical="https://next.useplunk.com/guides"
openGraph={{ openGraph={{
title: 'Email Marketing & Deliverability Guides | Plunk', title: 'Email Marketing & Deliverability Guides | Plunk',
description: description:
'Learn email best practices, authentication (DKIM, SPF, DMARC), deliverability optimization, and more.', 'Learn email best practices, authentication (DKIM, SPF, DMARC), deliverability optimization, and more.',
url: 'https://www.useplunk.com/guides', url: 'https://next.useplunk.com/guides',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk Guides'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk Guides'}],
}} }}
/> />
@@ -9,7 +9,7 @@ export default function TransactionalVsMarketingEmail() {
description="Understand the critical differences between transactional and marketing emails, including legal requirements, deliverability, and best practices." description="Understand the critical differences between transactional and marketing emails, including legal requirements, deliverability, and best practices."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="10 min" readTime="10 min"
canonical="https://www.useplunk.com/guides/transactional-vs-marketing-email" canonical="https://next.useplunk.com/guides/transactional-vs-marketing-email"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -10,7 +10,7 @@ export default function WhatIsDKIM() {
description="Learn how DKIM (DomainKeys Identified Mail) protects your emails from spoofing and improves deliverability. Complete guide with setup examples." description="Learn how DKIM (DomainKeys Identified Mail) protects your emails from spoofing and improves deliverability. Complete guide with setup examples."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="8 min" readTime="8 min"
canonical="https://www.useplunk.com/guides/what-is-dkim" canonical="https://next.useplunk.com/guides/what-is-dkim"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -10,7 +10,7 @@ export default function WhatIsDMARC() {
description="Learn how DMARC works with SPF and DKIM to protect your domain from email spoofing. Complete setup guide with policy examples." description="Learn how DMARC works with SPF and DKIM to protect your domain from email spoofing. Complete setup guide with policy examples."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="9 min" readTime="9 min"
canonical="https://www.useplunk.com/guides/what-is-dmarc" canonical="https://next.useplunk.com/guides/what-is-dmarc"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
@@ -10,7 +10,7 @@ export default function WhatIsSPF() {
description="Learn how SPF records work, prevent email spoofing, and improve deliverability. Complete guide with setup examples and best practices." description="Learn how SPF records work, prevent email spoofing, and improve deliverability. Complete guide with setup examples and best practices."
lastUpdated="2025-12-20" lastUpdated="2025-12-20"
readTime="7 min" readTime="7 min"
canonical="https://www.useplunk.com/guides/what-is-spf" canonical="https://next.useplunk.com/guides/what-is-spf"
> >
{/* Introduction */} {/* Introduction */}
<section id="introduction" className="mb-12"> <section id="introduction" className="mb-12">
+2 -2
View File
@@ -110,8 +110,8 @@ export default function Index() {
<span data-custom-class="body_text"> <span data-custom-class="body_text">
Visit our website <bdt className="block-component" /> at{' '} Visit our website <bdt className="block-component" /> at{' '}
<bdt className="question"> <bdt className="question">
<a href="https://www.useplunk.com" target="_blank" data-custom-class="link"> <a href="https://next.useplunk.com" target="_blank" data-custom-class="link">
https://www.useplunk.com https://next.useplunk.com
</a> </a>
</bdt> </bdt>
<span style={{fontSize: '15px'}}> <span style={{fontSize: '15px'}}>
+4 -4
View File
@@ -390,8 +390,8 @@ export default function Index() {
data-id="fdf30452-99b8-c68b-5cdf-34af764cd1fd" data-id="fdf30452-99b8-c68b-5cdf-34af764cd1fd"
data-type="question" data-type="question"
> >
<a href="https://www.useplunk.com" target="_blank" data-custom-class="link"> <a href="https://next.useplunk.com" target="_blank" data-custom-class="link">
https://www.useplunk.com https://next.useplunk.com
</a> </a>
</bdt>{' '} </bdt>{' '}
website as well as any other media form, media channel, mobile website or mobile application related, website as well as any other media form, media channel, mobile website or mobile application related,
@@ -3165,8 +3165,8 @@ export default function Index() {
data-id="d10c7fd7-0685-12ac-c717-cbc45ff916d1" data-id="d10c7fd7-0685-12ac-c717-cbc45ff916d1"
data-type="question" data-type="question"
> >
<a href="https://www.useplunk.com/privacy" target="_blank" data-custom-class="link"> <a href="https://next.useplunk.com/privacy" target="_blank" data-custom-class="link">
https://www.useplunk.com/privacy https://next.useplunk.com/privacy
</a> </a>
</bdt> </bdt>
</strong> </strong>
+3 -3
View File
@@ -32,13 +32,13 @@ export default function ToolsIndex() {
<NextSeo <NextSeo
title="Free Email Tools | Markdown to Email & Email Verification | Plunk" title="Free Email Tools | Markdown to Email & Email Verification | Plunk"
description="Free tools for email developers: Convert markdown to email-safe HTML and verify email addresses instantly. No sign-up required." description="Free tools for email developers: Convert markdown to email-safe HTML and verify email addresses instantly. No sign-up required."
canonical="https://www.useplunk.com/tools" canonical="https://next.useplunk.com/tools"
openGraph={{ openGraph={{
title: 'Free Email Tools | Markdown to Email & Email Verification | Plunk', title: 'Free Email Tools | Markdown to Email & Email Verification | Plunk',
description: description:
'Free tools for email developers: Convert markdown to email-safe HTML and verify email addresses instantly.', 'Free tools for email developers: Convert markdown to email-safe HTML and verify email addresses instantly.',
url: 'https://www.useplunk.com/tools', url: 'https://next.useplunk.com/tools',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk Email Tools'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk Email Tools'}],
}} }}
/> />
@@ -28,13 +28,13 @@ export default function MarkdownToEmail() {
<NextSeo <NextSeo
title="Free Markdown to Email HTML Converter | Plunk" title="Free Markdown to Email HTML Converter | Plunk"
description="Convert markdown and rich text to email-safe HTML instantly. Free online tool with live preview. Perfect for email developers and marketers." description="Convert markdown and rich text to email-safe HTML instantly. Free online tool with live preview. Perfect for email developers and marketers."
canonical="https://www.useplunk.com/tools/markdown-to-email" canonical="https://next.useplunk.com/tools/markdown-to-email"
openGraph={{ openGraph={{
title: 'Free Markdown to Email HTML Converter | Plunk', title: 'Free Markdown to Email HTML Converter | Plunk',
description: description:
'Convert markdown and rich text to email-safe HTML instantly. Free online tool with live preview.', 'Convert markdown and rich text to email-safe HTML instantly. Free online tool with live preview.',
url: 'https://www.useplunk.com/tools/markdown-to-email', url: 'https://next.useplunk.com/tools/markdown-to-email',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk Email HTML Converter'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk Email HTML Converter'}],
}} }}
/> />
@@ -36,12 +36,12 @@ export default function VerifyEmailPage() {
<NextSeo <NextSeo
title="Free Email Verification Tool | Check Email Validity | Plunk" title="Free Email Verification Tool | Check Email Validity | Plunk"
description="Verify email addresses instantly. Check for typos, disposable domains, MX records, and more. Free email validation tool with detailed results." description="Verify email addresses instantly. Check for typos, disposable domains, MX records, and more. Free email validation tool with detailed results."
canonical="https://www.useplunk.com/tools/verify-email" canonical="https://next.useplunk.com/tools/verify-email"
openGraph={{ openGraph={{
title: 'Free Email Verification Tool | Check Email Validity | Plunk', title: 'Free Email Verification Tool | Check Email Validity | Plunk',
description: 'Verify email addresses instantly. Check for typos, disposable domains, MX records, and more.', description: 'Verify email addresses instantly. Check for typos, disposable domains, MX records, and more.',
url: 'https://www.useplunk.com/tools/verify-email', url: 'https://next.useplunk.com/tools/verify-email',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk Email Verification Tool'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk Email Verification Tool'}],
}} }}
/> />
+8 -10
View File
@@ -33,7 +33,7 @@ const faqs: FAQ[] = [
'ActiveCampaign starts at $29/month for basic features and quickly scales to $149/month or more for automation features. Plunk uses pay-as-you-go pricing—you only pay for emails sent. For email-focused needs, Plunk typically costs 50-80% less than ActiveCampaign while providing the same email automation capabilities.', 'ActiveCampaign starts at $29/month for basic features and quickly scales to $149/month or more for automation features. Plunk uses pay-as-you-go pricing—you only pay for emails sent. For email-focused needs, Plunk typically costs 50-80% less than ActiveCampaign while providing the same email automation capabilities.',
}, },
{ {
question: 'Can Plunk match ActiveCampaign\'s automation capabilities?', question: "Can Plunk match ActiveCampaign's automation capabilities?",
answer: answer:
'For email automation, yes. Plunk supports workflow automation, event-based triggers, and audience segmentation just like ActiveCampaign. The difference is Plunk focuses purely on email, while ActiveCampaign includes CRM, sales automation, and ML-powered recommendations. If you need email automation without sales/CRM features, Plunk delivers the same capability with simpler implementation.', 'For email automation, yes. Plunk supports workflow automation, event-based triggers, and audience segmentation just like ActiveCampaign. The difference is Plunk focuses purely on email, while ActiveCampaign includes CRM, sales automation, and ML-powered recommendations. If you need email automation without sales/CRM features, Plunk delivers the same capability with simpler implementation.',
}, },
@@ -45,7 +45,7 @@ const faqs: FAQ[] = [
{ {
question: 'What ActiveCampaign features does Plunk not have?', question: 'What ActiveCampaign features does Plunk not have?',
answer: answer:
'Plunk focuses on email, so it doesn\'t include ActiveCampaign\'s CRM, sales pipeline management, lead scoring, SMS marketing, or machine learning features. If you need those, ActiveCampaign is better. If you want powerful email automation without the enterprise complexity, Plunk is the simpler choice.', "Plunk focuses on email, so it doesn't include ActiveCampaign's CRM, sales pipeline management, lead scoring, SMS marketing, or machine learning features. If you need those, ActiveCampaign is better. If you want powerful email automation without the enterprise complexity, Plunk is the simpler choice.",
}, },
]; ];
@@ -58,13 +58,13 @@ export default function ActiveCampaignComparison() {
<NextSeo <NextSeo
title="ActiveCampaign Alternative: Open-Source & Affordable | Plunk" title="ActiveCampaign Alternative: Open-Source & Affordable | Plunk"
description="Powerful email automation without ActiveCampaign's complexity and cost. Open-source, developer-friendly, pay-as-you-go pricing. No CRM bloat." description="Powerful email automation without ActiveCampaign's complexity and cost. Open-source, developer-friendly, pay-as-you-go pricing. No CRM bloat."
canonical="https://www.useplunk.com/vs/activecampaign" canonical="https://next.useplunk.com/vs/activecampaign"
openGraph={{ openGraph={{
title: 'ActiveCampaign Alternative: Open-Source & Affordable | Plunk', title: 'ActiveCampaign Alternative: Open-Source & Affordable | Plunk',
description: description:
"Powerful email automation without ActiveCampaign's complexity and cost. Open-source, developer-friendly, pay-as-you-go pricing.", "Powerful email automation without ActiveCampaign's complexity and cost. Open-source, developer-friendly, pay-as-you-go pricing.",
url: 'https://www.useplunk.com/vs/activecampaign', url: 'https://next.useplunk.com/vs/activecampaign',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs ActiveCampaign'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs ActiveCampaign'}],
}} }}
/> />
@@ -233,9 +233,7 @@ export default function ActiveCampaignComparison() {
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-20 text-center'} className={'mb-20 text-center'}
> >
<h2 className={'text-5xl font-bold tracking-tight text-neutral-900'}> <h2 className={'text-5xl font-bold tracking-tight text-neutral-900'}>Automation Without Complexity</h2>
Automation Without Complexity
</h2>
</motion.div> </motion.div>
<div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}>
@@ -318,8 +316,8 @@ export default function ActiveCampaignComparison() {
</div> </div>
<h3 className={'mt-6 text-xl font-semibold text-neutral-900'}>Open Source</h3> <h3 className={'mt-6 text-xl font-semibold text-neutral-900'}>Open Source</h3>
<p className={'mt-3 leading-relaxed text-neutral-600'}> <p className={'mt-3 leading-relaxed text-neutral-600'}>
AGPL-3.0 licensed. Full transparency into how your emails are processed. Contribute features, AGPL-3.0 licensed. Full transparency into how your emails are processed. Contribute features, understand
understand the system. ActiveCampaign is proprietary. the system. ActiveCampaign is proprietary.
</p> </p>
</motion.div> </motion.div>
+11 -15
View File
@@ -25,7 +25,7 @@ const faqs: FAQ[] = [
{ {
question: 'When should I choose Bento over Plunk?', question: 'When should I choose Bento over Plunk?',
answer: answer:
'Choose Bento if you need an all-in-one platform with CRM, live chat, and customer relationship features alongside email. Bento is designed for small businesses and creators who want everything in one place. Choose Plunk if you\'re a developer who needs focused email automation without CRM bloat—perfect for integrating email into your product.', "Choose Bento if you need an all-in-one platform with CRM, live chat, and customer relationship features alongside email. Bento is designed for small businesses and creators who want everything in one place. Choose Plunk if you're a developer who needs focused email automation without CRM bloat—perfect for integrating email into your product.",
}, },
{ {
question: 'What is the pricing difference between Plunk and Bento?', question: 'What is the pricing difference between Plunk and Bento?',
@@ -45,7 +45,7 @@ const faqs: FAQ[] = [
{ {
question: 'Is migration from Bento to Plunk easy?', question: 'Is migration from Bento to Plunk easy?',
answer: answer:
'For email features, yes. Export your contacts from Bento, import them to Plunk, recreate your workflows using our API or dashboard, and integrate Plunk into your application. If you rely heavily on Bento\'s CRM, live chat, or multi-channel features, you\'ll need separate tools for those. Most email-only migrations take a few hours.', "For email features, yes. Export your contacts from Bento, import them to Plunk, recreate your workflows using our API or dashboard, and integrate Plunk into your application. If you rely heavily on Bento's CRM, live chat, or multi-channel features, you'll need separate tools for those. Most email-only migrations take a few hours.",
}, },
]; ];
@@ -58,13 +58,13 @@ export default function BentoComparison() {
<NextSeo <NextSeo
title="Bento Alternative: Developer-First Email Platform | Plunk" title="Bento Alternative: Developer-First Email Platform | Plunk"
description="Open-source alternative to Bento. API-first email platform without CRM bloat. Self-hostable, pay-as-you-go pricing, built for developers." description="Open-source alternative to Bento. API-first email platform without CRM bloat. Self-hostable, pay-as-you-go pricing, built for developers."
canonical="https://www.useplunk.com/vs/bento" canonical="https://next.useplunk.com/vs/bento"
openGraph={{ openGraph={{
title: 'Bento Alternative: Developer-First Email Platform | Plunk', title: 'Bento Alternative: Developer-First Email Platform | Plunk',
description: description:
'Open-source alternative to Bento. API-first email platform without CRM bloat. Self-hostable, pay-as-you-go pricing.', 'Open-source alternative to Bento. API-first email platform without CRM bloat. Self-hostable, pay-as-you-go pricing.',
url: 'https://www.useplunk.com/vs/bento', url: 'https://next.useplunk.com/vs/bento',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Bento'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Bento'}],
}} }}
/> />
@@ -233,9 +233,7 @@ export default function BentoComparison() {
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-20 text-center'} className={'mb-20 text-center'}
> >
<h2 className={'text-5xl font-bold tracking-tight text-neutral-900'}> <h2 className={'text-5xl font-bold tracking-tight text-neutral-900'}>Developer-First Email Platform</h2>
Developer-First Email Platform
</h2>
</motion.div> </motion.div>
<div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}> <div className={'grid gap-px bg-neutral-200 sm:grid-cols-2 lg:grid-cols-3'}>
@@ -339,8 +337,8 @@ export default function BentoComparison() {
</div> </div>
<h3 className={'mt-6 text-xl font-semibold text-neutral-900'}>Self-Hostable</h3> <h3 className={'mt-6 text-xl font-semibold text-neutral-900'}>Self-Hostable</h3>
<p className={'mt-3 leading-relaxed text-neutral-600'}> <p className={'mt-3 leading-relaxed text-neutral-600'}>
Deploy on your infrastructure with Docker. Full data control, compliance-ready, no vendor lock-in. Deploy on your infrastructure with Docker. Full data control, compliance-ready, no vendor lock-in. Bento
Bento is cloud-only. is cloud-only.
</p> </p>
</motion.div> </motion.div>
@@ -360,8 +358,8 @@ export default function BentoComparison() {
</div> </div>
<h3 className={'mt-6 text-xl font-semibold text-neutral-900'}>Email-Focused</h3> <h3 className={'mt-6 text-xl font-semibold text-neutral-900'}>Email-Focused</h3>
<p className={'mt-3 leading-relaxed text-neutral-600'}> <p className={'mt-3 leading-relaxed text-neutral-600'}>
Do one thing exceptionally well: email. No feature bloat, no CRM complexity, no multi-channel Do one thing exceptionally well: email. No feature bloat, no CRM complexity, no multi-channel confusion.
confusion. Just powerful email automation. Just powerful email automation.
</p> </p>
</motion.div> </motion.div>
</div> </div>
@@ -394,9 +392,7 @@ export default function BentoComparison() {
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mx-auto max-w-3xl text-center'} className={'mx-auto max-w-3xl text-center'}
> >
<h2 className={'text-5xl font-bold tracking-tight text-neutral-900'}> <h2 className={'text-5xl font-bold tracking-tight text-neutral-900'}>Get focused email automation</h2>
Get focused email automation
</h2>
<p className={'mt-6 text-lg text-neutral-600'}> <p className={'mt-6 text-lg text-neutral-600'}>
Join developers choosing focused email solutions over all-in-one complexity. Start free, no credit card Join developers choosing focused email solutions over all-in-one complexity. Start free, no credit card
required. required.
+3 -3
View File
@@ -57,13 +57,13 @@ export default function BrevoComparison() {
<NextSeo <NextSeo
title="Brevo (Sendinblue) Alternative: Developer-First & Open Source | Plunk" title="Brevo (Sendinblue) Alternative: Developer-First & Open Source | Plunk"
description="Plunk offers a simpler, developer-focused alternative to Brevo with pay-as-you-go pricing, open-source code, and self-hosting. No contact limits." description="Plunk offers a simpler, developer-focused alternative to Brevo with pay-as-you-go pricing, open-source code, and self-hosting. No contact limits."
canonical="https://www.useplunk.com/vs/brevo" canonical="https://next.useplunk.com/vs/brevo"
openGraph={{ openGraph={{
title: 'Brevo (Sendinblue) Alternative: Developer-First & Open Source | Plunk', title: 'Brevo (Sendinblue) Alternative: Developer-First & Open Source | Plunk',
description: description:
'Plunk offers a simpler, developer-focused alternative to Brevo with pay-as-you-go pricing, open-source code, and self-hosting.', 'Plunk offers a simpler, developer-focused alternative to Brevo with pay-as-you-go pricing, open-source code, and self-hosting.',
url: 'https://www.useplunk.com/vs/brevo', url: 'https://next.useplunk.com/vs/brevo',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Brevo'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Brevo'}],
}} }}
/> />
+5 -7
View File
@@ -45,7 +45,7 @@ const faqs: FAQ[] = [
{ {
question: 'How easy is it to migrate from ConvertKit to Plunk?', question: 'How easy is it to migrate from ConvertKit to Plunk?',
answer: answer:
'Migration is straightforward. Export your subscribers from ConvertKit as CSV, import them to Plunk via our API or dashboard, recreate your email sequences using our workflow builder, and update your forms to use Plunk\'s API. Most migrations can be completed in a few hours. You\'ll need to rebuild landing pages separately if you rely on ConvertKit\'s landing page feature.', "Migration is straightforward. Export your subscribers from ConvertKit as CSV, import them to Plunk via our API or dashboard, recreate your email sequences using our workflow builder, and update your forms to use Plunk's API. Most migrations can be completed in a few hours. You'll need to rebuild landing pages separately if you rely on ConvertKit's landing page feature.",
}, },
]; ];
@@ -58,13 +58,13 @@ export default function ConvertkitComparison() {
<NextSeo <NextSeo
title="ConvertKit Alternative for Developers | Plunk" title="ConvertKit Alternative for Developers | Plunk"
description="Developer-first alternative to ConvertKit. Pay per email instead of per subscriber. Open-source, self-hostable, with powerful automation—no landing page bloat." description="Developer-first alternative to ConvertKit. Pay per email instead of per subscriber. Open-source, self-hostable, with powerful automation—no landing page bloat."
canonical="https://www.useplunk.com/vs/convertkit" canonical="https://next.useplunk.com/vs/convertkit"
openGraph={{ openGraph={{
title: 'ConvertKit Alternative for Developers | Plunk', title: 'ConvertKit Alternative for Developers | Plunk',
description: description:
'Developer-first alternative to ConvertKit. Pay per email instead of per subscriber. Open-source, self-hostable, with powerful automation.', 'Developer-first alternative to ConvertKit. Pay per email instead of per subscriber. Open-source, self-hostable, with powerful automation.',
url: 'https://www.useplunk.com/vs/convertkit', url: 'https://next.useplunk.com/vs/convertkit',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs ConvertKit'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs ConvertKit'}],
}} }}
/> />
@@ -141,9 +141,7 @@ export default function ConvertkitComparison() {
transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}} transition={{duration: 0.7, ease: [0.22, 1, 0.36, 1]}}
className={'mb-16 text-center'} className={'mb-16 text-center'}
> >
<h2 className={'text-5xl font-bold tracking-tight text-neutral-900'}> <h2 className={'text-5xl font-bold tracking-tight text-neutral-900'}>Pay for Emails, Not Subscribers</h2>
Pay for Emails, Not Subscribers
</h2>
<p className={'mt-4 text-lg text-neutral-600'}>Pricing that grows with usage, not list size</p> <p className={'mt-4 text-lg text-neutral-600'}>Pricing that grows with usage, not list size</p>
</motion.div> </motion.div>
+3 -3
View File
@@ -53,13 +53,13 @@ export default function CustomerioComparison() {
<NextSeo <NextSeo
title="Customer.io Alternative: Open-Source & Developer-Focused | Plunk" title="Customer.io Alternative: Open-Source & Developer-Focused | Plunk"
description="Compare Plunk and Customer.io. Customer.io is powerful but complex. Plunk is open-source, developer-friendly, with simple workflows and transparent pricing." description="Compare Plunk and Customer.io. Customer.io is powerful but complex. Plunk is open-source, developer-friendly, with simple workflows and transparent pricing."
canonical="https://www.useplunk.com/vs/customerio" canonical="https://next.useplunk.com/vs/customerio"
openGraph={{ openGraph={{
title: 'Customer.io Alternative: Open-Source & Developer-Focused | Plunk', title: 'Customer.io Alternative: Open-Source & Developer-Focused | Plunk',
description: description:
'Compare Plunk and Customer.io. Plunk is open-source, developer-friendly, with simple workflows and transparent pricing.', 'Compare Plunk and Customer.io. Plunk is open-source, developer-friendly, with simple workflows and transparent pricing.',
url: 'https://www.useplunk.com/vs/customerio', url: 'https://next.useplunk.com/vs/customerio',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Customer.io'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Customer.io'}],
}} }}
/> />
+3 -3
View File
@@ -96,13 +96,13 @@ export default function CompetitorsIndex() {
<NextSeo <NextSeo
title="Plunk vs Email Competitors | Compare Email Platforms" title="Plunk vs Email Competitors | Compare Email Platforms"
description="Compare Plunk with Postmark, SendGrid, Mailgun, Mailchimp, ConvertKit, ActiveCampaign, Klaviyo, MailerLite, and more. See why Plunk offers transactional emails plus marketing features in one open-source platform." description="Compare Plunk with Postmark, SendGrid, Mailgun, Mailchimp, ConvertKit, ActiveCampaign, Klaviyo, MailerLite, and more. See why Plunk offers transactional emails plus marketing features in one open-source platform."
canonical="https://www.useplunk.com/vs" canonical="https://next.useplunk.com/vs"
openGraph={{ openGraph={{
title: 'Plunk vs Email Competitors | Compare Email Platforms', title: 'Plunk vs Email Competitors | Compare Email Platforms',
description: description:
'Compare Plunk with 13 leading email platforms. Transactional + marketing emails in one open-source solution.', 'Compare Plunk with 13 leading email platforms. Transactional + marketing emails in one open-source solution.',
url: 'https://www.useplunk.com/vs', url: 'https://next.useplunk.com/vs',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Competitors'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Competitors'}],
}} }}
/> />
+4 -4
View File
@@ -45,7 +45,7 @@ const faqs: FAQ[] = [
{ {
question: 'What Klaviyo features does Plunk not have?', question: 'What Klaviyo features does Plunk not have?',
answer: answer:
'Plunk focuses on email, so it doesn\'t include Klaviyo\'s SMS marketing, native e-commerce platform integrations, AI-powered product recommendations, or predictive analytics. If you need those enterprise features and have the budget, Klaviyo is better. If you want powerful email automation at a fraction of the cost, Plunk delivers.', "Plunk focuses on email, so it doesn't include Klaviyo's SMS marketing, native e-commerce platform integrations, AI-powered product recommendations, or predictive analytics. If you need those enterprise features and have the budget, Klaviyo is better. If you want powerful email automation at a fraction of the cost, Plunk delivers.",
}, },
]; ];
@@ -58,13 +58,13 @@ export default function KlaviyoComparison() {
<NextSeo <NextSeo
title="Klaviyo Alternative: Affordable E-commerce Email | Plunk" title="Klaviyo Alternative: Affordable E-commerce Email | Plunk"
description="E-commerce email automation without Klaviyo's price tag. Pay-as-you-go pricing, open-source, self-hostable. Perfect for developers building e-commerce." description="E-commerce email automation without Klaviyo's price tag. Pay-as-you-go pricing, open-source, self-hostable. Perfect for developers building e-commerce."
canonical="https://www.useplunk.com/vs/klaviyo" canonical="https://next.useplunk.com/vs/klaviyo"
openGraph={{ openGraph={{
title: 'Klaviyo Alternative: Affordable E-commerce Email | Plunk', title: 'Klaviyo Alternative: Affordable E-commerce Email | Plunk',
description: description:
"E-commerce email automation without Klaviyo's price tag. Pay-as-you-go pricing, open-source, self-hostable.", "E-commerce email automation without Klaviyo's price tag. Pay-as-you-go pricing, open-source, self-hostable.",
url: 'https://www.useplunk.com/vs/klaviyo', url: 'https://next.useplunk.com/vs/klaviyo',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Klaviyo'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Klaviyo'}],
}} }}
/> />
+3 -3
View File
@@ -57,13 +57,13 @@ export default function LoopsComparison() {
<NextSeo <NextSeo
title="Loops Alternative: Open Source & Self-Hostable | Plunk" title="Loops Alternative: Open Source & Self-Hostable | Plunk"
description="Plunk offers an open-source alternative to Loops with pay-as-you-go pricing, self-hosting, and no contact limits. Same modern features, full transparency." description="Plunk offers an open-source alternative to Loops with pay-as-you-go pricing, self-hosting, and no contact limits. Same modern features, full transparency."
canonical="https://www.useplunk.com/vs/loops" canonical="https://next.useplunk.com/vs/loops"
openGraph={{ openGraph={{
title: 'Loops Alternative: Open Source & Self-Hostable | Plunk', title: 'Loops Alternative: Open Source & Self-Hostable | Plunk',
description: description:
'Plunk offers an open-source alternative to Loops with pay-as-you-go pricing, self-hosting, and no contact limits.', 'Plunk offers an open-source alternative to Loops with pay-as-you-go pricing, self-hosting, and no contact limits.',
url: 'https://www.useplunk.com/vs/loops', url: 'https://next.useplunk.com/vs/loops',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Loops'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Loops'}],
}} }}
/> />
+3 -3
View File
@@ -58,13 +58,13 @@ export default function MailchimpComparison() {
<NextSeo <NextSeo
title="Mailchimp Alternative for Developers | Plunk" title="Mailchimp Alternative for Developers | Plunk"
description="Plunk is Mailchimp for developers: code-first email platform with modern API. Pay per email, not per contact. Transactional + marketing in one platform." description="Plunk is Mailchimp for developers: code-first email platform with modern API. Pay per email, not per contact. Transactional + marketing in one platform."
canonical="https://www.useplunk.com/vs/mailchimp" canonical="https://next.useplunk.com/vs/mailchimp"
openGraph={{ openGraph={{
title: 'Mailchimp Alternative for Developers | Plunk', title: 'Mailchimp Alternative for Developers | Plunk',
description: description:
'Plunk is Mailchimp for developers: code-first email platform with modern API. Pay per email, not per contact.', 'Plunk is Mailchimp for developers: code-first email platform with modern API. Pay per email, not per contact.',
url: 'https://www.useplunk.com/vs/mailchimp', url: 'https://next.useplunk.com/vs/mailchimp',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Mailchimp'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Mailchimp'}],
}} }}
/> />
+9 -9
View File
@@ -25,7 +25,7 @@ const faqs: FAQ[] = [
{ {
question: 'What is the main difference between Plunk and MailerLite?', question: 'What is the main difference between Plunk and MailerLite?',
answer: answer:
'The main difference is that Plunk is open-source and self-hostable, while MailerLite is proprietary SaaS. Plunk uses pay-per-email pricing versus MailerLite\'s pay-per-subscriber model. Both are developer-friendly, but Plunk is API-first with full code transparency, while MailerLite focuses more on visual email builders with good API support.', "The main difference is that Plunk is open-source and self-hostable, while MailerLite is proprietary SaaS. Plunk uses pay-per-email pricing versus MailerLite's pay-per-subscriber model. Both are developer-friendly, but Plunk is API-first with full code transparency, while MailerLite focuses more on visual email builders with good API support.",
}, },
{ {
question: 'Is Plunk more expensive than MailerLite?', question: 'Is Plunk more expensive than MailerLite?',
@@ -40,12 +40,12 @@ const faqs: FAQ[] = [
{ {
question: 'Does Plunk have a drag-and-drop builder like MailerLite?', question: 'Does Plunk have a drag-and-drop builder like MailerLite?',
answer: answer:
'Plunk has a basic email editor, but most users manage templates using HTML/code for full control, version control, and reusability. MailerLite excels at visual drag-and-drop building for non-technical users. If you\'re a developer who prefers code-based templates, Plunk is better. If you need rich visual builders for marketers, MailerLite is better.', "Plunk has a basic email editor, but most users manage templates using HTML/code for full control, version control, and reusability. MailerLite excels at visual drag-and-drop building for non-technical users. If you're a developer who prefers code-based templates, Plunk is better. If you need rich visual builders for marketers, MailerLite is better.",
}, },
{ {
question: 'How does Plunk\'s API compare to MailerLite?', question: "How does Plunk's API compare to MailerLite?",
answer: answer:
'Both have modern REST APIs, but Plunk\'s API is designed with developers as the primary user. Plunk prioritizes API-first workflows, making it easier to integrate email into your application. MailerLite has a good API but is built UI-first with API as secondary. For programmatic email sending and automation, Plunk offers a superior developer experience.', "Both have modern REST APIs, but Plunk's API is designed with developers as the primary user. Plunk prioritizes API-first workflows, making it easier to integrate email into your application. MailerLite has a good API but is built UI-first with API as secondary. For programmatic email sending and automation, Plunk offers a superior developer experience.",
}, },
]; ];
@@ -58,13 +58,13 @@ export default function MailerliteComparison() {
<NextSeo <NextSeo
title="MailerLite Alternative: Open-Source & Self-Hostable | Plunk" title="MailerLite Alternative: Open-Source & Self-Hostable | Plunk"
description="The truly developer-first MailerLite alternative. Open-source, self-hostable, pay per email not per subscriber. Modern API, full transparency." description="The truly developer-first MailerLite alternative. Open-source, self-hostable, pay per email not per subscriber. Modern API, full transparency."
canonical="https://www.useplunk.com/vs/mailerlite" canonical="https://next.useplunk.com/vs/mailerlite"
openGraph={{ openGraph={{
title: 'MailerLite Alternative: Open-Source & Self-Hostable | Plunk', title: 'MailerLite Alternative: Open-Source & Self-Hostable | Plunk',
description: description:
'The truly developer-first MailerLite alternative. Open-source, self-hostable, pay per email not per subscriber.', 'The truly developer-first MailerLite alternative. Open-source, self-hostable, pay per email not per subscriber.',
url: 'https://www.useplunk.com/vs/mailerlite', url: 'https://next.useplunk.com/vs/mailerlite',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs MailerLite'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs MailerLite'}],
}} }}
/> />
@@ -360,8 +360,8 @@ export default function MailerliteComparison() {
</div> </div>
<h3 className={'mt-6 text-xl font-semibold text-neutral-900'}>Unlimited Contacts</h3> <h3 className={'mt-6 text-xl font-semibold text-neutral-900'}>Unlimited Contacts</h3>
<p className={'mt-3 leading-relaxed text-neutral-600'}> <p className={'mt-3 leading-relaxed text-neutral-600'}>
Store unlimited contacts without additional cost. Your database grows freely, pricing stays Store unlimited contacts without additional cost. Your database grows freely, pricing stays predictable
predictable based on emails sent. based on emails sent.
</p> </p>
</motion.div> </motion.div>
</div> </div>
+3 -3
View File
@@ -53,13 +53,13 @@ export default function MailgunComparison() {
<NextSeo <NextSeo
title="Mailgun Alternative: Open-Source with Marketing & Automation | Plunk" title="Mailgun Alternative: Open-Source with Marketing & Automation | Plunk"
description="Compare Plunk and Mailgun. Mailgun focuses on transactional emails, while Plunk adds marketing campaigns, workflows, and is open-source." description="Compare Plunk and Mailgun. Mailgun focuses on transactional emails, while Plunk adds marketing campaigns, workflows, and is open-source."
canonical="https://www.useplunk.com/vs/mailgun" canonical="https://next.useplunk.com/vs/mailgun"
openGraph={{ openGraph={{
title: 'Mailgun Alternative: Open-Source with Marketing & Automation | Plunk', title: 'Mailgun Alternative: Open-Source with Marketing & Automation | Plunk',
description: description:
'Compare Plunk and Mailgun. Mailgun is excellent for transactional emails. Plunk adds marketing, workflows, and is open-source.', 'Compare Plunk and Mailgun. Mailgun is excellent for transactional emails. Plunk adds marketing, workflows, and is open-source.',
url: 'https://www.useplunk.com/vs/mailgun', url: 'https://next.useplunk.com/vs/mailgun',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Mailgun'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Mailgun'}],
}} }}
/> />
+3 -3
View File
@@ -54,13 +54,13 @@ export default function PostmarkComparison() {
<NextSeo <NextSeo
title="Postmark Alternative: Transactional + Marketing Emails | Plunk" title="Postmark Alternative: Transactional + Marketing Emails | Plunk"
description="Plunk offers everything Postmark has for transactional emails, plus marketing campaigns, workflows, and segmentation. Open-source and self-hostable." description="Plunk offers everything Postmark has for transactional emails, plus marketing campaigns, workflows, and segmentation. Open-source and self-hostable."
canonical="https://www.useplunk.com/vs/postmark" canonical="https://next.useplunk.com/vs/postmark"
openGraph={{ openGraph={{
title: 'Postmark Alternative: Transactional + Marketing Emails | Plunk', title: 'Postmark Alternative: Transactional + Marketing Emails | Plunk',
description: description:
'Plunk offers everything Postmark has for transactional emails, plus marketing campaigns, workflows, and segmentation.', 'Plunk offers everything Postmark has for transactional emails, plus marketing campaigns, workflows, and segmentation.',
url: 'https://www.useplunk.com/vs/postmark', url: 'https://next.useplunk.com/vs/postmark',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Postmark'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Postmark'}],
}} }}
/> />
+3 -3
View File
@@ -53,13 +53,13 @@ export default function ResendComparison() {
<NextSeo <NextSeo
title="Plunk vs Resend: Open-Source Alternative with Marketing | Plunk" title="Plunk vs Resend: Open-Source Alternative with Marketing | Plunk"
description="Compare Plunk and Resend. Resend focuses on transactional emails, while Plunk adds marketing campaigns, workflows, and is open-source. Choose based on your needs." description="Compare Plunk and Resend. Resend focuses on transactional emails, while Plunk adds marketing campaigns, workflows, and is open-source. Choose based on your needs."
canonical="https://www.useplunk.com/vs/resend" canonical="https://next.useplunk.com/vs/resend"
openGraph={{ openGraph={{
title: 'Plunk vs Resend: Open-Source Alternative with Marketing', title: 'Plunk vs Resend: Open-Source Alternative with Marketing',
description: description:
'Compare Plunk and Resend. Resend focuses on transactional emails, while Plunk adds marketing, workflows, and is open-source.', 'Compare Plunk and Resend. Resend focuses on transactional emails, while Plunk adds marketing, workflows, and is open-source.',
url: 'https://www.useplunk.com/vs/resend', url: 'https://next.useplunk.com/vs/resend',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs Resend'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs Resend'}],
}} }}
/> />
+3 -3
View File
@@ -57,13 +57,13 @@ export default function SendGridComparison() {
<NextSeo <NextSeo
title="SendGrid Alternative: Pay-As-You-Go & Open Source | Plunk" title="SendGrid Alternative: Pay-As-You-Go & Open Source | Plunk"
description="Plunk offers pay-as-you-go pricing instead of monthly subscriptions, with a modern API and no complex setup. Open source alternative to SendGrid." description="Plunk offers pay-as-you-go pricing instead of monthly subscriptions, with a modern API and no complex setup. Open source alternative to SendGrid."
canonical="https://www.useplunk.com/vs/sendgrid" canonical="https://next.useplunk.com/vs/sendgrid"
openGraph={{ openGraph={{
title: 'SendGrid Alternative: Pay-As-You-Go & Open Source | Plunk', title: 'SendGrid Alternative: Pay-As-You-Go & Open Source | Plunk',
description: description:
'Plunk offers pay-as-you-go pricing instead of monthly subscriptions, with a modern API and no complex setup.', 'Plunk offers pay-as-you-go pricing instead of monthly subscriptions, with a modern API and no complex setup.',
url: 'https://www.useplunk.com/vs/sendgrid', url: 'https://next.useplunk.com/vs/sendgrid',
images: [{url: 'https://www.useplunk.com/assets/card.png', alt: 'Plunk vs SendGrid'}], images: [{url: 'https://next.useplunk.com/assets/card.png', alt: 'Plunk vs SendGrid'}],
}} }}
/> />
+1 -1
View File
@@ -1,5 +1,5 @@
/** @type {import('next-sitemap').IConfig} */ /** @type {import('next-sitemap').IConfig} */
module.exports = { module.exports = {
siteUrl: process.env.NEXT_PUBLIC_DASHBOARD_URI || 'https://app.useplunk.com', siteUrl: process.env.NEXT_PUBLIC_DASHBOARD_URI || 'https://next-app.useplunk.com',
generateRobotsTxt: true, generateRobotsTxt: true,
}; };
+1 -1
View File
@@ -26,7 +26,7 @@ export const baseOptions: BaseLayoutProps = {
{ {
icon: <AppWindowIcon />, icon: <AppWindowIcon />,
text: 'Dashboard', text: 'Dashboard',
url: 'https://app.useplunk.com', url: 'https://next-app.useplunk.com',
}, },
{ {
icon: <GithubIcon />, icon: <GithubIcon />,
+4 -4
View File
@@ -25,23 +25,23 @@ export default function Layout({children}: {children: ReactNode}) {
{/* Open Graph / Facebook */} {/* Open Graph / Facebook */}
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:url" content="https://docs.useplunk.com/" /> <meta property="og:url" content="https://next-wiki.useplunk.com/" />
<meta property="og:title" content="Plunk Documentation" /> <meta property="og:title" content="Plunk Documentation" />
<meta <meta
property="og:description" property="og:description"
content="Documentation for Plunk, the open-source email platform. Learn how to integrate Plunk into your application and manage your email communications." content="Documentation for Plunk, the open-source email platform. Learn how to integrate Plunk into your application and manage your email communications."
/> />
<meta property="og:image" content="https://docs.useplunk.com/assets/card.png" /> <meta property="og:image" content="https://next-wiki.useplunk.com/assets/card.png" />
{/* Twitter */} {/* Twitter */}
<meta property="twitter:card" content="summary_large_image" /> <meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content="https://docs.useplunk.com/" /> <meta property="twitter:url" content="https://next-wiki.useplunk.com/" />
<meta property="twitter:title" content="Plunk Documentation" /> <meta property="twitter:title" content="Plunk Documentation" />
<meta <meta
property="twitter:description" property="twitter:description"
content="Documentation for Plunk, the open-source email platform. Learn how to integrate Plunk into your application and manage your email communications." content="Documentation for Plunk, the open-source email platform. Learn how to integrate Plunk into your application and manage your email communications."
/> />
<meta property="twitter:image" content="https://docs.useplunk.com/assets/card.png" /> <meta property="twitter:image" content="https://next-wiki.useplunk.com/assets/card.png" />
{/* Fonts */} {/* Fonts */}
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
+2 -2
View File
@@ -29,7 +29,7 @@ const getRuntimeEnv = (key: keyof NonNullable<typeof window.__ENV__>) => {
}; };
export function ApiUrl({path = ''}: {path?: string}) { export function ApiUrl({path = ''}: {path?: string}) {
const baseUrl = getRuntimeEnv('API_URI') || process.env.NEXT_PUBLIC_API_URI || 'https://api.useplunk.com'; const baseUrl = getRuntimeEnv('API_URI') || process.env.NEXT_PUBLIC_API_URI || 'https://next-api.useplunk.com';
return ( return (
<code> <code>
{baseUrl} {baseUrl}
@@ -40,7 +40,7 @@ export function ApiUrl({path = ''}: {path?: string}) {
export function DashboardUrl({path = ''}: {path?: string}) { export function DashboardUrl({path = ''}: {path?: string}) {
const baseUrl = const baseUrl =
getRuntimeEnv('DASHBOARD_URI') || process.env.NEXT_PUBLIC_DASHBOARD_URI || 'https://app.useplunk.com'; getRuntimeEnv('DASHBOARD_URI') || process.env.NEXT_PUBLIC_DASHBOARD_URI || 'https://next-app.useplunk.com';
return ( return (
<code> <code>
{baseUrl} {baseUrl}
@@ -303,7 +303,7 @@ Successful API requests return a standardized format with `success: true` and a
```typescript ```typescript
try { try {
const response = await fetch('https://api.useplunk.com/v1/track', { const response = await fetch('https://next-api.useplunk.com/v1/track', {
method: 'POST', method: 'POST',
headers: { headers: {
'Authorization': `Bearer ${publicKey}`, 'Authorization': `Bearer ${publicKey}`,
@@ -361,7 +361,7 @@ try {
import requests import requests
response = requests.post( response = requests.post(
'https://api.useplunk.com/v1/track', 'https://next-api.useplunk.com/v1/track',
headers={ headers={
'Authorization': f'Bearer {public_key}', 'Authorization': f'Bearer {public_key}',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
@@ -426,7 +426,7 @@ Request IDs are included in:
```javascript ```javascript
// Example: Logging request ID in your application // Example: Logging request ID in your application
const response = await fetch('https://api.useplunk.com/v1/send', { const response = await fetch('https://next-api.useplunk.com/v1/send', {
// ... your request // ... your request
}); });
+7 -11
View File
@@ -1,24 +1,20 @@
import { visit } from 'unist-util-visit'; import {visit} from 'unist-util-visit';
// Default URLs that will be replaced at container startup by sed // Default URLs that will be replaced at container startup by sed
const API_URL = process.env.NEXT_PUBLIC_API_URI || 'https://api.useplunk.com'; const API_URL = process.env.NEXT_PUBLIC_API_URI || 'https://next-api.useplunk.com';
const DASHBOARD_URL = process.env.NEXT_PUBLIC_DASHBOARD_URI || 'https://app.useplunk.com'; const DASHBOARD_URL = process.env.NEXT_PUBLIC_DASHBOARD_URI || 'https://next-app.useplunk.com';
export function remarkReplaceEnv() { export function remarkReplaceEnv() {
return (tree) => { return tree => {
visit(tree, ['code', 'inlineCode', 'text', 'link'], (node) => { visit(tree, ['code', 'inlineCode', 'text', 'link'], node => {
// Replace in text values // Replace in text values
if (node.value && typeof node.value === 'string') { if (node.value && typeof node.value === 'string') {
node.value = node.value node.value = node.value.replace(/\{\{API_URL\}\}/g, API_URL).replace(/\{\{DASHBOARD_URL\}\}/g, DASHBOARD_URL);
.replace(/\{\{API_URL\}\}/g, API_URL)
.replace(/\{\{DASHBOARD_URL\}\}/g, DASHBOARD_URL);
} }
// Replace in link URLs // Replace in link URLs
if (node.url && typeof node.url === 'string') { if (node.url && typeof node.url === 'string') {
node.url = node.url node.url = node.url.replace(/\{\{API_URL\}\}/g, API_URL).replace(/\{\{DASHBOARD_URL\}\}/g, DASHBOARD_URL);
.replace(/\{\{API_URL\}\}/g, API_URL)
.replace(/\{\{DASHBOARD_URL\}\}/g, DASHBOARD_URL);
} }
}); });
}; };
+3 -3
View File
@@ -13,7 +13,7 @@ const __dirname = path.dirname(__filename);
function findMdxFiles(dir, fileList = []) { function findMdxFiles(dir, fileList = []) {
const files = fs.readdirSync(dir); const files = fs.readdirSync(dir);
files.forEach((file) => { files.forEach(file => {
const filePath = path.join(dir, file); const filePath = path.join(dir, file);
const stat = fs.statSync(filePath); const stat = fs.statSync(filePath);
@@ -46,7 +46,7 @@ function filePathToUrl(filePath) {
} }
const config = { const config = {
siteUrl: process.env.NEXT_PUBLIC_WIKI_URI || 'https://docs.useplunk.com', siteUrl: process.env.NEXT_PUBLIC_WIKI_URI || 'https://next-wiki.useplunk.com',
generateRobotsTxt: true, generateRobotsTxt: true,
additionalPaths: async () => { additionalPaths: async () => {
const contentDocsPath = path.join(__dirname, 'content', 'docs'); const contentDocsPath = path.join(__dirname, 'content', 'docs');
@@ -55,7 +55,7 @@ const config = {
const mdxFiles = findMdxFiles(contentDocsPath); const mdxFiles = findMdxFiles(contentDocsPath);
// Convert to sitemap entries // Convert to sitemap entries
return mdxFiles.map((filePath) => ({ return mdxFiles.map(filePath => ({
loc: filePathToUrl(filePath), loc: filePathToUrl(filePath),
changefreq: 'weekly', changefreq: 'weekly',
priority: 0.7, priority: 0.7,
+15 -13
View File
@@ -6,12 +6,12 @@
"version": "1.0.0", "version": "1.0.0",
"contact": { "contact": {
"name": "Plunk Support", "name": "Plunk Support",
"url": "https://useplunk.com" "url": "https://next.useplunk.com"
} }
}, },
"servers": [ "servers": [
{ {
"url": "https://api.useplunk.com", "url": "https://next-api.useplunk.com",
"description": "Production server" "description": "Production server"
} }
], ],
@@ -694,7 +694,16 @@
"description": "Array of human-readable reasons describing the verification results" "description": "Array of human-readable reasons describing the verification results"
} }
}, },
"required": ["email", "valid", "isDisposable", "isTypo", "isPlusAddressed", "domainExists", "hasMxRecords", "reasons"] "required": [
"email",
"valid",
"isDisposable",
"isTypo",
"isPlusAddressed",
"domainExists",
"hasMxRecords",
"reasons"
]
} }
} }
}, },
@@ -711,9 +720,7 @@
"isPlusAddressed": false, "isPlusAddressed": false,
"domainExists": true, "domainExists": true,
"hasMxRecords": true, "hasMxRecords": true,
"reasons": [ "reasons": ["Email appears to be valid"]
"Email appears to be valid"
]
} }
} }
}, },
@@ -730,10 +737,7 @@
"domainExists": false, "domainExists": false,
"hasMxRecords": false, "hasMxRecords": false,
"suggestedEmail": "[email protected]", "suggestedEmail": "[email protected]",
"reasons": [ "reasons": ["Possible typo detected, did you mean gmail.com?", "Domain does not exist"]
"Possible typo detected, did you mean gmail.com?",
"Domain does not exist"
]
} }
} }
}, },
@@ -749,9 +753,7 @@
"isPlusAddressed": false, "isPlusAddressed": false,
"domainExists": true, "domainExists": true,
"hasMxRecords": true, "hasMxRecords": true,
"reasons": [ "reasons": ["Email appears to be valid"]
"Email appears to be valid"
]
} }
} }
} }
+3 -9
View File
@@ -6,7 +6,7 @@ interface FooterProps {
landingUrl?: string; landingUrl?: string;
} }
export function Footer({projectId, landingUrl = 'https://www.useplunk.com'}: FooterProps) { export function Footer({projectId, landingUrl = 'https://next.useplunk.com'}: FooterProps) {
return ( return (
<Section className="border-t border-gray-100 bg-gray-50 px-8 py-8"> <Section className="border-t border-gray-100 bg-gray-50 px-8 py-8">
<Text className="mb-4 mt-0 text-center text-xs leading-relaxed text-gray-600"> <Text className="mb-4 mt-0 text-center text-xs leading-relaxed text-gray-600">
@@ -22,17 +22,11 @@ export function Footer({projectId, landingUrl = 'https://www.useplunk.com'}: Foo
Plunk Plunk
</Link> </Link>
{' • '} {' • '}
<Link <Link href={`${landingUrl}/privacy`} className="text-gray-500 no-underline hover:text-gray-700">
href={`${landingUrl}/privacy`}
className="text-gray-500 no-underline hover:text-gray-700"
>
Privacy Privacy
</Link> </Link>
{' • '} {' • '}
<Link <Link href={`${landingUrl}/terms`} className="text-gray-500 no-underline hover:text-gray-700">
href={`${landingUrl}/terms`}
className="text-gray-500 no-underline hover:text-gray-700"
>
Terms Terms
</Link> </Link>
</Text> </Text>
@@ -20,8 +20,8 @@ export function BillingLimitExceededEmail({
usage = 10000, usage = 10000,
limit = 10000, limit = 10000,
sourceType = 'Transactional', sourceType = 'Transactional',
dashboardUrl = 'https://app.useplunk.com', dashboardUrl = 'https://next-app.useplunk.com',
landingUrl = 'https://www.useplunk.com', landingUrl = 'https://next.useplunk.com',
}: BillingLimitExceededEmailProps) { }: BillingLimitExceededEmailProps) {
return ( return (
<EmailLayout> <EmailLayout>
@@ -22,8 +22,8 @@ export function BillingLimitWarningEmail({
limit = 10000, limit = 10000,
percentage = 85, percentage = 85,
sourceType = 'Transactional', sourceType = 'Transactional',
dashboardUrl = 'https://app.useplunk.com', dashboardUrl = 'https://next-app.useplunk.com',
landingUrl = 'https://www.useplunk.com', landingUrl = 'https://next.useplunk.com',
}: BillingLimitWarningEmailProps) { }: BillingLimitWarningEmailProps) {
const percentageRounded = Math.round(percentage); const percentageRounded = Math.round(percentage);
const remaining = limit - usage; const remaining = limit - usage;
@@ -13,7 +13,7 @@ interface EmailVerificationEmailProps {
export function EmailVerificationEmail({ export function EmailVerificationEmail({
email = '[email protected]', email = '[email protected]',
verificationUrl = 'https://api.useplunk.com/auth/verify-email?token=abc123', verificationUrl = 'https://api.useplunk.com/auth/verify-email?token=abc123',
landingUrl = 'https://www.useplunk.com', landingUrl = 'https://next.useplunk.com',
}: EmailVerificationEmailProps) { }: EmailVerificationEmailProps) {
return ( return (
<EmailLayout> <EmailLayout>
+3 -5
View File
@@ -12,17 +12,15 @@ interface PasswordResetEmailProps {
export function PasswordResetEmail({ export function PasswordResetEmail({
email = '[email protected]', email = '[email protected]',
resetUrl = 'https://app.useplunk.com/auth/reset-password?token=abc123', resetUrl = 'https://next-app.useplunk.com/auth/reset-password?token=abc123',
landingUrl = 'https://www.useplunk.com', landingUrl = 'https://next.useplunk.com',
}: PasswordResetEmailProps) { }: PasswordResetEmailProps) {
return ( return (
<EmailLayout> <EmailLayout>
<Header /> <Header />
<Section className="px-8 pb-10 pt-10"> <Section className="px-8 pb-10 pt-10">
<Heading className="mb-2 mt-0 text-2xl font-semibold tracking-tight text-gray-900"> <Heading className="mb-2 mt-0 text-2xl font-semibold tracking-tight text-gray-900">Reset your password</Heading>
Reset your password
</Heading>
<Text className="mb-8 mt-0 text-base leading-relaxed text-gray-600"> <Text className="mb-8 mt-0 text-base leading-relaxed text-gray-600">
We received a request to reset your password. Click the button below to create a new password. We received a request to reset your password. Click the button below to create a new password.
@@ -16,8 +16,8 @@ export function ProjectDisabledEmail({
projectName = 'My Project', projectName = 'My Project',
projectId = 'proj_example123', projectId = 'proj_example123',
violations = ['Bounce rate exceeded 10% threshold', 'Complaint rate exceeded 0.5% threshold'], violations = ['Bounce rate exceeded 10% threshold', 'Complaint rate exceeded 0.5% threshold'],
dashboardUrl = 'https://app.useplunk.com', dashboardUrl = 'https://next-app.useplunk.com',
landingUrl = 'https://www.useplunk.com', landingUrl = 'https://next.useplunk.com',
}: ProjectDisabledEmailProps) { }: ProjectDisabledEmailProps) {
return ( return (
<EmailLayout> <EmailLayout>