|
|
|
| OVERVIEW |
|
Kampaign runs locally and uses your SMTP credentials to send. Contacts, templates, and campaign history stay on your machine. There is no hosted backend in the loop. The source is available on GitHub if you want to review or extend it.
|
| FEATURES |
- CSV and Excel import
- Template editor with placeholders
- Preview before sending
- Campaign history
|
- Broadcast and personalized attachments
- SMTP connection test
- Docker and Node.js support
- Open source
|
|
| REQUIREMENTS |
- Node.js 18+ for local dev
- Docker and Docker Compose if you prefer containers
- SMTP credentials from your email provider
|
| CONFIGURATION (.env) |
|
Create a .env file in the project root:
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your_email_here
SMTP_APP_PASSWORD=your_app_password_here
APP_PORT=3000
Keep this file local. It is excluded from Git and Docker builds.
SMTP transport uses secure=false by default. Use port 587 for TLS.
Getting credentials:
- Gmail: create an App Password in your Google Account security settings. App Passwords guide
- Other providers: use their SMTP username and password or token from their help docs.
|
| RUN THE APP |
Development (no Docker)
npm install
npm run dev
Open: http://localhost:3000
|
Production (no Docker)
npm run build
npm start
|
Docker (Production)
docker compose -f docker-compose.prod.yml build
docker compose -f docker-compose.prod.yml up
Open: http://localhost:3000
|
Docker (Development)
docker compose -f docker-compose.dev.yml up
Hot reload with containerized dependencies.
|
|
| DASHBOARD |
|
View past campaigns stored in IndexedDB. Each row shows name, subject, recipients, completion date, and status. Click VIEW to open details and logs.
|
| IMPORT RECIPIENTS |
Formats: CSV, XLS, XLSX. The first sheet is used.
How it works:
- Each column becomes a template placeholder.
- A preview shows the first 10 rows and detected headers.
Tip: Make sure one column contains the recipient email address.
|
| DESIGN TEMPLATE |
Subject: supports placeholders like {name}.
Body: rich text editor with headings, lists, alignment, links, and code blocks.
Placeholders:
- Use {column_name} to insert a field.
- Click a header chip to insert it, or type "{" to autocomplete.
|
| ATTACHMENTS |
Two modes:
- Broadcast: sent to every recipient.
- Personalized: matched per recipient using a filename rule.
How to use:
- Upload files.
- Enable custom rules if you want a mix of broadcast and personalized files.
- Mark each file as Broadcast or Personalized.
- Add one or more rules. A rule is a filename pattern with placeholders.
Rule examples:
{name}_invitation.pdf
{student_id}_report.pdf
Matching behavior:
- The rule is rendered for each recipient using their data.
- If a file with that exact name exists in your uploads, it is attached.
- If there is no match, that personalized file is skipped for that recipient.
Tips:
- Use exact filenames, including extensions.
- Keep placeholder names identical to the column headers.
|
| CONFIGURE & SEND |
Summary: counts recipients, attachments, and readiness.
Campaign name: used in history and log files.
Email header: choose the column that contains recipient email addresses.
SMTP test: verify credentials before sending.
Send flow:
- Click SEND NOW to validate required fields.
- Preview a rendered email for a random contact.
- Use RANDOMIZE to preview another contact.
- Confirm SEND to deliver.
Validation rules:
- Required: subject, at least one contact, selected recipient header.
- Warnings: missing campaign name, empty body, or no attachments.
Schedule: the button is UI only for now.
|
| SETTINGS (SMTP CONFIGURATION) |
|
This page collects SMTP host, port, username, and app password. Saving is UI only. SMTP tests use values from .env.
|
| TEMPLATE PLACEHOLDERS |
Syntax: use curly braces with column headers, for example {first_name}.
If a placeholder does not match a column or the value is empty, it stays unchanged.
|
| DATA & STORAGE |
|
Session data lives in a client store and resets after send or refresh. Campaign history is stored in IndexedDB. Delivery logs are saved to logs/campaigns. Attachments are written to tmp during send, then removed.
|
| INTERNAL API |
GET /api/smtp/test tests SMTP credentials from .env.
POST /api/campaign/send accepts multipart/form-data with a JSON payload and files, sends mail, and returns counts and log file path.
GET /api/campaign/logs/[campaignSlug] returns log entries for the campaign.
|
| TROUBLESHOOTING |
SMTP not configured
Check SMTP_HOST, SMTP_PORT, SMTP_USER, and SMTP_APP_PASSWORD in .env.
Gmail login fails
Use an App Password and enable 2FA.
Placeholders not replaced
Match column names exactly, including case.
Personalized attachments missing
Check that filenames match the rendered rule and include the extension.
|
| PROJECT STRUCTURE |
app/
(dashboard)/ Dashboard + campaign detail pages
(campaign)/ Import -> Design -> Attachments -> Configure flow
api/ SMTP test, send, logs
settings/ SMTP settings UI (currently UI-only)
components/
design/ Rich text editor
shared/ Header, sidebar, drag/drop, footer
lib/
api.ts Client API helpers
store/ Zustand state
template/ Placeholder rendering
server/ SMTP config + logging
db/ IndexedDB (Dexie) storage
|
|
Kampaign documentation - local-first bulk email automation
|
BACK TO TOP
|
|
|