A beautiful email template platform for creating and sending holiday greetings, marketing emails, and newsletters.
Features a bold Neobrutalism design with an intuitive drag-and-drop block-based editor.
One-click FREE deployment of your personalized email campaigns.
Live Demo Β· Tutorial Β· Issues
Share SendJoy
Pioneering the future of email marketing. Built for creators and marketers.
Tech Stack
Important
SendJoy is a modern email template platform built with Next.js 15, React 19, and TypeScript. It combines a visual drag-and-drop editor with the Resend API for seamless email delivery. Features include 7 block types, real-time preview, theme customization, contact management, and a 5-step sending wizard.
π Table of Contents
- SendJoy
- π Introduction
- β¨ Key Features
- π οΈ Tech Stack
- ποΈ Architecture
- β‘οΈ Performance
- π Getting Started
- π³ Deployment
- π Usage Guide
- π¦ Template System
- π API Reference
- π¨ Neobrutalism Design System
- π Security
- β¨οΈ Development
- π€ Contributing
- π License
- πββοΈ Author
- π¨ Troubleshooting
- π FAQ
SendJoy is designed for creators, marketers, and businesses who want to send beautiful, personalized emails without coding. Our visual editor makes it easy to create professional email templates with a unique Neobrutalism aesthetic that stands out in any inbox.
Whether you're sending holiday greetings, product announcements, or newsletters, SendJoy provides all the tools you need from template creation to delivery tracking.
Note
- No coding required - visual drag-and-drop interface
- Resend API key required for email sending
- All data stored locally in browser (privacy-first)
- Works on desktop and tablet browsers
| No installation required! Visit our live demo to experience SendJoy. |
|---|
Tip
β Star us to receive all release notifications from GitHub without delay!
β Star History
Experience next-generation email design with our intuitive visual editor. Create stunning emails with drag-and-drop simplicity while maintaining full creative control.
graph LR
subgraph Editor["Visual Editor"]
direction TB
BLOCKS[Block Palette] --> CANVAS[Email Canvas]
CANVAS --> PREVIEW[Live Preview]
THEME[Theme Panel] --> CANVAS
end
subgraph Actions["Editor Actions"]
UNDO[Undo/Redo<br/>50 states]
SAVE[Auto-save<br/>localStorage]
VIEW[Device Toggle<br/>Desktop/Mobile]
end
Editor --> Actions
style BLOCKS fill:#DC2626,color:#fff
style CANVAS fill:#16A34A,color:#fff
style PREVIEW fill:#F59E0B,color:#fff
style THEME fill:#7C3AED,color:#fff
Key capabilities include:
- π¨ Drag-and-drop editing - Reorder blocks with intuitive drag-and-drop using @dnd-kit
- π¦ 7 block types - Header, Text, Image, Button, Wishes List, Divider, Footer
- ποΈ Real-time preview - See changes instantly in the canvas
- π± Device preview - Toggle between desktop (600px) and mobile (375px) views
- π¨ Theme customization - 9+ color options with full color pickers
- β©οΈ Undo/Redo - Full history tracking with up to 50 states
- πΎ Auto-save - Templates persist to browser localStorage
Revolutionary 5-step wizard that guides you from template selection to successful delivery with real-time progress tracking.
graph LR
S1["1. Select<br/>Template"] --> S2["2. Choose<br/>Recipients"]
S2 --> S3["3. Customize<br/>Variables"]
S3 --> S4["4. Preview<br/>Email"]
S4 --> S5["5. Send &<br/>Track"]
style S1 fill:#DC2626,color:#fff
style S2 fill:#F59E0B,color:#fff
style S3 fill:#16A34A,color:#fff
style S4 fill:#7C3AED,color:#fff
style S5 fill:#3B82F6,color:#fff
Wizard Features:
- π§ Template Selection - Choose from presets, custom, or Resend templates
- π₯ Recipient Selection - Choose individual or all contacts
- β¨ Personalization - Dynamic variables like
{{recipientName}} - π Real Preview - See actual rendered email before sending
- π Progress Tracking - Visual progress bar during batch sending
- β Result Summary - Per-recipient success/failure reporting
Flexible contact management with multiple import methods and full CRUD operations.
flowchart LR
subgraph Input["Input Methods"]
MANUAL[Manual Entry]
CSV[CSV Import]
RESEND[Resend Sync]
end
subgraph Storage["Contact Storage"]
LOCAL[(localStorage)]
CLOUD[(Resend Audience)]
end
MANUAL --> LOCAL
CSV --> LOCAL
RESEND --> LOCAL
LOCAL <-.->|Sync| CLOUD
style MANUAL fill:#DC2626,color:#fff
style CSV fill:#16A34A,color:#fff
style RESEND fill:#F59E0B,color:#fff
style LOCAL fill:#FEF3C7
style CLOUD fill:#000,color:#fff
Management Features:
- βοΈ Manual Entry - Add contacts one by one with form validation
- π CSV Import - Bulk import contacts (Email, FirstName, LastName columns)
- π Resend Sync - Import contacts from Resend Audiences
- βοΈ Edit & Delete - Full CRUD operations with modal dialogs
- π Search - Filter contacts by email, first name, or last name
Beyond the core features, SendJoy includes:
- π¨ Quick Setup - Deploy in under 1 minute with one-click installation
- π 6 Preset Templates - Ready-to-use professionally designed templates
- π Privacy First - All data stored locally in browser
- π Neobrutalism UI - Bold, distinctive design that stands out
- π± Responsive Layout - Works on desktop and tablet
- π― Block Visibility - Show/hide blocks without deleting
- π Template Copying - Duplicate any template for customization
- π·οΈ Category Filtering - Filter by Holiday, Marketing, Newsletter, or Custom
- π€ Welcome Onboarding - Guided setup for first-time users
- β Help System - Context-aware help modal
β¨ More features are continuously being added as the project evolves.
Frontend Stack:
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 15.1.2 | React framework with App Router |
| React | 19.0.0 | UI component library |
| TypeScript | 5.7 | Type safety |
| Tailwind CSS | 3.4 | Utility-first CSS |
| shadcn/ui | latest | UI component system |
| Lucide React | 0.468 | Icon library |
| @dnd-kit | 6.1+ | Drag-and-drop functionality |
| Zustand | 5.0.2 | State management |
Backend & Services:
| Technology | Version | Purpose |
|---|---|---|
| React Email | 0.0.31 | Email template rendering |
| Resend | 4.0.1 | Email delivery API |
| Vercel | - | Hosting & serverless functions |
Additional Libraries:
| Library | Purpose |
|---|---|
| Radix UI | Unstyled UI primitives |
| class-variance-authority | CSS variant management |
| tailwind-merge | Tailwind class merging |
| tailwindcss-animate | Animation plugin |
| clsx | Conditional class names |
Tip
Each technology was carefully selected for production readiness, developer experience, and long-term maintainability.
graph TB
subgraph Client["Browser (Client)"]
UI[React UI]
ZUSTAND[(Zustand Store)]
LS[(LocalStorage)]
UI <--> ZUSTAND
ZUSTAND --> LS
end
subgraph Server["Next.js Server (Vercel)"]
API[API Routes]
RENDER[React Email<br/>Renderer]
API --> RENDER
end
subgraph External["External Services"]
RESEND[Resend API]
RESEND_T[Resend Templates]
RESEND_A[Resend Audiences]
end
UI -->|HTTP Requests| API
API -->|Send Email| RESEND
API -->|Manage Templates| RESEND_T
API -->|Sync Contacts| RESEND_A
RESEND -->|Delivery Status| API
RESEND_T -->|Template Data| API
RESEND_A -->|Contact Data| API
style UI fill:#DC2626,color:#fff
style ZUSTAND fill:#7C3AED,color:#fff
style LS fill:#FEF3C7
style API fill:#16A34A,color:#fff
style RENDER fill:#F59E0B,color:#fff
style RESEND fill:#000,color:#fff
style RESEND_T fill:#000,color:#fff
style RESEND_A fill:#000,color:#fff
graph TD
HOME["/\nDashboard"] --> TEMPLATES["/templates\nTemplate Library"]
HOME --> CONTACTS["/contacts\nContact Manager"]
HOME --> SEND["/send\nSending Wizard"]
HOME --> SETTINGS["/settings\nConfiguration"]
TEMPLATES --> EDITOR["/templates/[id]/edit\nVisual Editor"]
TEMPLATES --> RESEND_T["/templates/resend\nResend Templates"]
style HOME fill:#DC2626,color:#fff
style TEMPLATES fill:#16A34A,color:#fff
style CONTACTS fill:#F59E0B,color:#fff
style SEND fill:#7C3AED,color:#fff
style SETTINGS fill:#3B82F6,color:#fff
style EDITOR fill:#EC4899,color:#fff
style RESEND_T fill:#000,color:#fff
sequenceDiagram
participant User
participant Browser
participant API as Next.js API
participant Resend as Resend API
User->>Browser: Configure Settings
Browser->>Browser: Save to LocalStorage
User->>Browser: Create/Edit Template
Browser->>Browser: Save to LocalStorage
User->>Browser: Start Send Wizard
Browser->>Browser: Select Template & Recipients
loop For Each Recipient
Browser->>API: POST /api/preview
Note right of API: Replace variables<br/>{{recipientName}}, etc.
API-->>Browser: Personalized HTML
Browser->>API: POST /api/send
API->>Resend: Send via Resend
Resend-->>API: {id, success}
API-->>Browser: Response
Browser->>Browser: Update Progress
end
Browser-->>User: Show Results Summary
graph TB
subgraph Zustand["Zustand Store"]
THEME[Theme State]
BLOCKS[Blocks State]
HISTORY[History Stack]
end
subgraph LocalStorage
TEMPLATES[(Templates)]
CONTACTS[(Contacts)]
SETTINGS[(Settings)]
ONBOARDING[(Onboarding)]
end
subgraph Components
EDITOR_UI[Editor UI]
SIDEBAR_UI[Sidebar]
PREVIEW_UI[Preview Panel]
end
Components --> Zustand
Zustand --> LocalStorage
style THEME fill:#7C3AED,color:#fff
style BLOCKS fill:#7C3AED,color:#fff
style HISTORY fill:#7C3AED,color:#fff
send-joy/
βββ app/ # Next.js App Router
β βββ page.tsx # Dashboard homepage
β βββ layout.tsx # Root layout with sidebar
β βββ globals.css # Global styles + Tailwind
β β
β βββ templates/ # Template pages
β β βββ page.tsx # Template library with filtering
β β βββ resend/page.tsx # Resend cloud templates
β β βββ [id]/edit/page.tsx # Visual editor with undo/redo
β β
β βββ contacts/page.tsx # Contact management with CSV
β βββ send/page.tsx # 5-step sending wizard
β βββ settings/page.tsx # Configuration page
β β
β βββ api/ # API Routes
β βββ send/route.ts # Email sending endpoint
β βββ preview/route.ts # Template rendering
β βββ contacts/route.ts # Resend contacts sync
β βββ resend-templates/ # Resend template management
β
βββ components/ # React Components
β βββ ui/ # shadcn/ui components
β βββ shared/ # Shared components
β βββ help/ # Help system
β βββ onboarding/ # Onboarding flow
β βββ progress/ # Progress tracking
β βββ settings/ # Settings components
β
βββ contexts/ # React Contexts
βββ hooks/ # Custom Hooks
βββ lib/ # Utilities
βββ types/ # TypeScript Definitions
βββ public/ # Static Assets
Key Metrics:
- β‘ 95+ Lighthouse Score across all categories
- π < 1s Time to First Byte (TTFB)
- π¨ < 100ms API response times
- π 99.9% uptime on Vercel
Performance Optimizations:
- π― LocalStorage Caching - All data cached locally for instant access
- π¦ Code Splitting - Automatic bundle optimization with Next.js
- πΌοΈ Image Optimization - Next.js Image component with WebP
- π Zustand Store - Efficient state management with minimal re-renders
Note
Performance metrics are measured using Lighthouse and continuously monitored in production.
| No installation required! Start using SendJoy immediately. |
|---|
- Visit https://send-joy.vercel.app/
- Go to Settings and enter your Resend API Key
- Add your contacts (manually, CSV, or sync from Resend)
- Choose a template and customize it
- Use the Send wizard to send emails!
Important
Ensure you have the following installed:
1. Clone Repository
git clone https://github.com/ChanMeng666/send-joy.git
cd send-joy2. Install Dependencies
# Using npm
npm install
# Using yarn
yarn install
# Using pnpm (recommended)
pnpm install3. Start Development Server
npm run devπ Success! Open http://localhost:3000 to view the application.
Important
Choose the deployment strategy that best fits your needs. Vercel is recommended for the easiest setup.
Vercel (Recommended)
Manual Deployment:
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel --prodOther Platforms:
| Deploy with Netlify | Deploy with Railway |
|---|---|
Note
SendJoy stores all configuration in browser localStorage. No server-side environment variables are required for basic operation.
For development, you may optionally set:
# Optional: For server-side Resend operations
RESEND_API_KEY="re_xxxxxxxxxxxxx"Getting Started:
- Configure Settings - Add your Resend API Key and sender email
- Add Contacts - Import via CSV, manual entry, or Resend sync
- Choose Template - Select from 6 presets or create custom
- Customize - Edit blocks, colors, and content
- Send - Use the 5-step wizard to deliver emails
| Variable | Description | Example Output |
|---|---|---|
{{recipientName}} |
Recipient's first name or email prefix | "John" |
{{senderName}} |
Configured sender name | "Jane Smith" |
{{currentYear}} |
Current year | "2025" |
{{nextYear}} |
Next year | "2026" |
Syntax Support:
- Local preview syntax:
{{variableName}}(camelCase) - Resend template syntax:
{{{VARIABLE_NAME}}}(UPPER_SNAKE_CASE)
All data is stored in browser localStorage (no server-side storage):
| Key | Content |
|---|---|
email-platform-templates |
Custom templates |
email-platform-contacts |
Local contacts |
email-platform-settings |
API key, sender info |
email-platform-onboarding |
First-visit and progress state |
email-platform-emails-sent |
Send count |
email-platform-sidebar-collapsed |
Sidebar collapse state |
| Template | Category | Description |
|---|---|---|
| Classic Christmas | Holiday | Red and green Neobrutalism Christmas greeting |
| New Year 2025 | Holiday | Purple and gold celebration theme |
| Chinese New Year | Holiday | Traditional red and gold with Year of the Snake |
| Birthday Wishes | Holiday | Pink and purple colorful celebration |
| Product Launch | Marketing | Gold and blue bold announcement |
| Weekly Newsletter | Newsletter | Green professional digest layout |
graph TB
subgraph Blocks["7 Block Types"]
HEADER[Header<br/>Title + Subtitle + Icons]
TEXT[Text<br/>Content + Alignment + Highlight]
IMAGE[Image<br/>URL + Caption + Border]
BUTTON[Button<br/>Text + URL + Style]
WISHES[Wishes<br/>Title + Item List]
DIVIDER[Divider<br/>Line/Icons/Spacer]
FOOTER[Footer<br/>Sender + LinkedIn + Message]
end
style HEADER fill:#DC2626,color:#fff
style TEXT fill:#16A34A,color:#fff
style IMAGE fill:#F59E0B,color:#fff
style BUTTON fill:#7C3AED,color:#fff
style WISHES fill:#3B82F6,color:#fff
style DIVIDER fill:#EC4899,color:#fff
style FOOTER fill:#000,color:#fff
| Block | Description | Editable Properties |
|---|---|---|
| Header | Title section | title, subtitle, showIcons, icons |
| Text | Paragraph content | content, alignment, highlightBox |
| Image | Photo or graphic | src, alt, caption, borderStyle, shadowColor |
| Button | Call-to-action link | text, url, style (primary/secondary/outline) |
| Wishes List | Bulleted list with icons | title, items (icon + text array) |
| Divider | Horizontal separator | style (line/icons/spacer), height |
| Footer | Sender signature | senderName, senderLabel, showLinkedIn, linkedInUrl, closingMessage |
graph LR
subgraph Colors["Color System"]
PRIMARY[Primary<br/>#DC2626]
SECONDARY[Secondary<br/>#16A34A]
ACCENT[Accent<br/>#F59E0B]
end
subgraph Variants["Color Variants"]
DARK[Dark Variant]
LIGHT[Light Variant]
end
PRIMARY --> DARK
PRIMARY --> LIGHT
SECONDARY --> DARK
SECONDARY --> LIGHT
ACCENT --> LIGHT
style PRIMARY fill:#DC2626,color:#fff
style SECONDARY fill:#16A34A,color:#fff
style ACCENT fill:#F59E0B,color:#fff
| Property | Default | Description |
|---|---|---|
primaryColor |
#DC2626 |
Headers, accents (red) |
primaryColorDark |
#B91C1C |
Dark variant |
primaryColorLight |
#FEE2E2 |
Light variant |
secondaryColor |
#16A34A |
Buttons, footers (green) |
secondaryColorDark |
#15803D |
Dark variant |
secondaryColorLight |
#DCFCE7 |
Light variant |
accentColor |
#F59E0B |
Highlights (gold) |
accentColorLight |
#FEF3C7 |
Light variant |
backgroundColor |
#1a1a2e |
Email body background |
surfaceColor |
#FFFBEB |
Content area background |
textColor |
#000000 |
Body text color |
borderColor |
#000000 |
Neobrutalism borders |
borderWidth |
4 |
Border thickness (px) |
shadowOffset |
8 |
Hard shadow offset (px) |
fontFamily |
Georgia, serif |
Font family |
Send an email via Resend.
// Request body
{
apiKey: string, // Resend API key
from: string, // Sender email (verified domain)
to: string | string[], // Recipient email(s)
subject: string, // Email subject
html: string // Rendered HTML content
}
// Response
{
success: boolean,
data?: { id: string },
error?: string
}Render template blocks to HTML.
// Request body
{
blocks: EmailBlock[], // Content blocks
theme: ThemeConfig, // Theme configuration
variables: Record<string, string> // Personalization variables
}
// Response
{
success: boolean,
html: string
}List contacts from Resend Audiences.
// Query params
?apiKey=re_xxx&audienceId=dc18b68d-xxx
// Response
{
success: boolean,
contacts: Array<{
email: string,
first_name?: string,
last_name?: string
}>
}Add or remove contacts from Resend Audience.
// POST Request body (add contact)
{
apiKey: string,
audienceId: string,
email: string,
firstName?: string,
lastName?: string
}
// DELETE Request body (remove contact)
{
apiKey: string,
audienceId: string,
email: string
}List all Resend cloud templates.
// Query params
?apiKey=re_xxx
// Response
{
success: boolean,
templates: Array<{
id: string,
name: string,
created_at: string
}>
}Duplicate a Resend template.
Publish a Resend template.
graph TB
subgraph Principles["Neobrutalism Characteristics"]
BORDER[Bold Borders<br/>4px solid black]
SHADOW[Hard Shadows<br/>8px offset, no blur]
COLOR[Vibrant Colors<br/>Primary, Secondary, Accent]
TYPE[Bold Typography<br/>High contrast]
end
style BORDER fill:#000,color:#fff
style SHADOW fill:#333,color:#fff
style COLOR fill:#DC2626,color:#fff
style TYPE fill:#16A34A,color:#fff
neo-red: #DC2626
neo-red-dark: #B91C1C
neo-green: #16A34A
neo-green-dark: #15803D
neo-gold: #F59E0B
neo-cream: #FEF3C7
neo-warm: #FFFBEBshadow-neo-sm: 2px 2px 0px black
shadow-neo: 4px 4px 0px black
shadow-neo-lg: 8px 8px 0px black
shadow-neo-red: 4px 4px 0px #DC2626
shadow-neo-green: 4px 4px 0px #16A34A
shadow-neo-gold: 4px 4px 0px #F59E0B- All data stored locally - Settings, contacts, templates in browser localStorage
- No server-side storage - Nothing persisted on the server
- API keys sent per-request - Not stored on server, sent directly to Resend
Warning
Never share your Resend API key publicly or commit it to version control.
- π Use different Resend API keys for development/production
- β Verify your sending domain in Resend for production use
- π« Never commit
.envfiles to version control - π Delete and recreate API keys if you suspect compromise
# Clone repository
git clone https://github.com/ChanMeng666/send-joy.git
cd send-joy
# Install dependencies
npm install
# Start development server
npm run dev
# Build for production
npm run build
# Start production server
npm start# Development
npm run dev # Start dev server on port 3000
# Production
npm run build # Build for production
npm start # Start production server
# Code Quality
npm run lint # ESLint check
npm run type-check # TypeScript check (if configured)We welcome contributions! Here's how you can help improve SendJoy:
1. Fork & Clone:
git clone https://github.com/ChanMeng666/send-joy.git
cd send-joy2. Create Branch:
git checkout -b feature/your-feature-name3. Make Changes:
- Follow TypeScript best practices
- Maintain Neobrutalism design consistency
- Test on both desktop and mobile views
- Update documentation as needed
4. Submit PR:
- Provide clear description
- Include screenshots for UI changes
- Reference related issues
|
|
|---|
This project is licensed under the MIT License - see the LICENSE file for details.
Open Source Benefits:
- β Commercial use allowed
- β Modification allowed
- β Distribution allowed
- β Private use allowed
Chan Meng Creator & Lead Developer |
Chan Meng
LinkedIn: chanmeng666
GitHub: ChanMeng666
Website: chanmeng.live
π§ Common Issues
Node.js Version Conflicts:
# Check Node.js version
node --version
# Use Node Version Manager
nvm install 18
nvm use 18Package Installation Failures:
# Clear npm cache
npm cache clean --force
# Delete node_modules and reinstall
rm -rf node_modules package-lock.json
npm installPort Already in Use:
# Find process using port 3000 (Linux/Mac)
lsof -i :3000
# Find process using port 3000 (Windows)
netstat -ano | findstr :3000
# Kill the process
kill -9 <PID> # Linux/Mac
taskkill /PID <PID> /F # WindowsEmails Not Sending:
- Verify your Resend API key is correct
- Check that your sender email domain is verified in Resend
- Ensure recipient email addresses are valid
Template Not Rendering:
- Check browser console for JavaScript errors
- Verify all required block properties are set
- Clear localStorage and try again
β Frequently Asked Questions
Q: Can I use SendJoy commercially? A: Yes, this project is licensed under MIT license, allowing commercial use.
Q: Do I need a Resend account? A: Yes, you need a free Resend account to send emails. Sign up at resend.com.
Q: Where is my data stored? A: All data (templates, contacts, settings) is stored in your browser's localStorage. Nothing is stored on our servers.
Q: Can I use custom fonts? A: Email clients have limited font support. We recommend using web-safe fonts like Georgia, Arial, or system fonts.
Q: How many emails can I send? A: This depends on your Resend plan. The free tier allows 100 emails/day.
Q: Is there mobile app support? A: SendJoy is a web application with responsive design. It works well on tablets but is optimized for desktop use.
Made with β€οΈ by Chan Meng
β Star us on GitHub β’ π Read the Tutorial β’ π Report Issues β’ π‘ Request Features
- Resend - Email delivery API
- React Email - Email template components
- shadcn/ui - Beautiful UI components
- @dnd-kit - Drag and drop toolkit
- Zustand - State management
- Vercel - Hosting platform