newsletter
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 6 GitHub stars
Code Warn
- network request — Outbound network request in package-lock.json
- network request — Outbound network request in package.json
Permissions Pass
- Permissions — No dangerous permissions requested
This tool is a comprehensive newsletter management system built for Laravel. It handles subscriber lists, campaigns, and email tracking, and includes an MCP server to enable AI assistant integrations.
Security Assessment
The overall risk is rated as Low. The project is a standard web application and API, so it naturally interacts with sensitive data like subscriber emails, campaign metrics, and user credentials. However, it does not request dangerous system permissions. The automated scan flagged outbound network requests in the package files, which is entirely expected and safe behavior for an application designed to send emails, connect to IMAP servers for bounce detection, and apply UTM tracking links. No hardcoded secrets or malicious shell command executions were detected in the audit.
Quality Assessment
The project uses the standard and highly permissive MIT license. It appears to be actively maintained, with repository activity occurring as recently as today. However, it currently suffers from extremely low community visibility. With only 6 GitHub stars, the tool has not been widely tested or adopted by the broader developer community. This means potential bugs or security vulnerabilities have not been vetted by a large audience.
Verdict
Use with caution: The code itself appears safe and functions as described, but the lack of widespread community adoption means you should perform your own security review before trusting it with production subscriber data.
Open Source Newsletter System
Newsletter System
Version 2.0.7 — Changelog
A complete newsletter management system for Laravel, built with Filament. Manage subscribers, campaigns, HTML templates, scheduled sending, and full tracking — all from a modern admin panel. Includes a REST API, OpenAPI documentation, and an MCP server for AI integrations.
Table of Contents
- Features
- User Management & Roles
- Requirements
- Installation
- Configuration
- Quick Start
- Sending Newsletters
- Monitoring & Analytics
- Rate Limiting
- REST API
- MCP Server (AI Integrations)
- Testing Tags
- Multilingual Support
- Public Routes
- Scheduled Tasks
- Artisan Commands
- Troubleshooting
Features
| Feature | Description |
|---|---|
| Subscriber Management | Import/export CSV, tagging, status management |
| Campaigns & Messages | Hierarchical organization of campaigns and messages |
| HTML Templates | Customizable templates with placeholder support |
| Scheduled Sending | Automatic delivery via cron |
| Full Tracking | Opens, clicks, and unsubscribe tracking |
| Targeting | Filter recipients by tags and status |
| Dashboard | Statistics and monitoring widgets |
| Rate Limiting | Configurable per-minute, per-hour, and per-day limits |
| Bounce Detection | IMAP integration for bounce processing |
| REST API | Full CRUD API with Sanctum authentication and OpenAPI docs |
| MCP Server | AI integration endpoint for Cursor, Claude Code, and other clients |
| Testing Tags | Mark tags as testing to exclude sends from production statistics |
| Multilingual | Admin panel in Italian, English, German, French, Spanish, Portuguese |
| UTM Tracking | Automatic UTM parameters on outbound newsletter links |
| User Roles | Three permission levels: Editor, Manager, Administrator |
User Management & Roles
The application supports three user roles with progressively broader permissions. Every user is assigned exactly one role, stored in the role column of the users table.
Roles
| Role | Description |
|---|---|
| Editor | Focused on content creation. Can create and manage draft messages within existing campaigns. |
| Manager | Full operational access. Manages campaigns, subscribers, tags, templates, and all message states. |
| Administrator | Everything a Manager can do, plus user management and API token management. |
Permission Matrix
| Area | Editor | Manager | Administrator |
|---|---|---|---|
| Dashboard | — | ✓ | ✓ |
| Campaigns (view) | ✓ | ✓ | ✓ |
| Campaigns (create/edit/delete) | — | ✓ | ✓ |
| Messages (create) | ✓ | ✓ | ✓ |
| Messages (view/edit/delete draft) | ✓ | ✓ | ✓ |
| Messages (view sent/sending) | — | ✓ | ✓ |
| Subscribers | — | ✓ | ✓ |
| Tags | — | ✓ | ✓ |
| Templates | — | ✓ | ✓ |
| Users | — | — | ✓ |
| API Tokens | — | — | ✓ |
| Newsletter Report API | — | ✓ | ✓ |
Navigation
- Editor — lands on the Campaigns page after login; the dashboard is not shown in navigation.
- Manager / Administrator — lands on the Dashboard; all navigation items are visible according to the matrix above.
- User menu — the API Tokens and Users links appear only for Administrators.
Managing Users
Administrators can create, edit, and delete users from the Users page in the admin panel. When creating or editing a user, the following fields are available:
- Name and Email (required)
- Password (required on create, optional on edit — leave blank to keep unchanged)
- Role — select Editor, Manager, or Administrator
- Locale — preferred language for the admin panel UI
An administrator cannot delete their own account.
Migrations
When upgrading from a version without roles, two migrations handle the transition:
add_role_to_users_table— adds therolecolumn (defaults toeditor).set_all_existing_users_to_legacy_administrator_role— promotes all pre-existing users toadministratorso they retain full access.
Requirements
- PHP 8.3+
- Laravel 13
- Filament 5
- Database (SQLite, MySQL, or PostgreSQL)
- Queue driver (database, Redis, etc.)
Installation
- Clone the repository and install dependencies:
git clone <repository-url> newsletter
cd newsletter
composer install
- Configure the environment:
cp .env.example .env
php artisan key:generate
- Run migrations:
php artisan migrate
- Build frontend assets:
npm install
npm run build
- Create an admin user (if not using seed data):
php artisan make:filament-user
- Generate API documentation (optional):
php artisan l5-swagger:generate
Configuration
Configure your SMTP settings in .env:
MAIL_MAILER=smtp
MAIL_HOST=your-smtp-host.com
MAIL_PORT=587
MAIL_USERNAME=your-username
MAIL_PASSWORD=your-password
MAIL_FROM_ADDRESS="[email protected]"
MAIL_FROM_NAME="${APP_NAME}"
Newsletter
| Variable | Description | Default |
|---|---|---|
NEWSLETTER_TRACKING_ENABLED |
Enable open/click tracking | true |
NEWSLETTER_RATE_LIMIT_PER_MINUTE |
Max sends per rolling minute (0 = no cap) |
0 |
NEWSLETTER_RATE_LIMIT_PER_HOUR |
Max sends per rolling hour (0 = no cap) |
0 |
NEWSLETTER_RATE_LIMIT_PER_DAY |
Max sends per rolling day (0 = no cap) |
0 |
See Rate limiting for behaviour and tuning.
IMAP (Bounce Detection)
Optional configuration for processing bounced emails:
NEWSLETTER_IMAP_HOST=imap.yourdomain.com
NEWSLETTER_IMAP_PORT=993
NEWSLETTER_IMAP_USERNAME=your-username
NEWSLETTER_IMAP_PASSWORD=your-password
NEWSLETTER_IMAP_ENCRYPTION=ssl
NEWSLETTER_IMAP_FOLDER=INBOX
API Documentation (Swagger)
To auto-generate the OpenAPI spec on every request in local development:
L5_SWAGGER_GENERATE_ALWAYS=true
For production, run php artisan l5-swagger:generate during deploy.
Quick Start
- Seed sample data (optional, recommended for testing):
php artisan newsletter:seed-data
- Start the queue worker:
./start-worker.sh
Or manually:
php artisan queue:work --tries=3 --timeout=90
- Access the admin panel:
- URL:
https://newsletter.test(Laravel Herd) orhttp://localhost:8000 - Default credentials (after seeding):
[email protected]/password
Sending Newsletters
Immediate Sending
- Go to Newsletter > Messages
- Create a new message or select an existing one
- Set status to Ready
- Click Send Now
- Emails are queued and sent automatically via the queue worker
Scheduled Sending
- Create or edit a message
- Set the Scheduled Date field
- The system sends automatically at the scheduled time (requires cron — see Scheduled Tasks)
Monitoring & Analytics
- Dashboard: Main KPIs and send statistics
- Messages: Status and send counts per message
- Message Details: Individual tracking (opens, clicks) per recipient
Rate Limiting
Configure how many emails the queue may send using rolling windows (stored in the app cache). Set a variable to 0 to turn off that cap; the other caps still apply.
| Env variable | Window | Typical use |
|---|---|---|
NEWSLETTER_RATE_LIMIT_PER_MINUTE |
~1 min | Burst control; low values cause jobs to release() often (short delays). |
NEWSLETTER_RATE_LIMIT_PER_HOUR |
~1 h | Provider hourly quotas. |
NEWSLETTER_RATE_LIMIT_PER_DAY |
~24 h | Daily provider caps. |
How sending works: for each queued send, SendNewsletterEmail checks daily, then hourly, then per-minute (App\Services\EmailRateLimiter). The send proceeds only if it fits under every enabled limit; otherwise the job is released with a delay and no quota is consumed for that attempt.
Throughput: in practice the tightest of your enabled limits dominates (e.g. high hourly but low per-minute still throttles bursts).
Estimated time: while a message is in Sending, the UI uses the same three env-driven values to approximate completion (Message::getEstimatedSendTime()).
Example (adjust to your SMTP limits):
NEWSLETTER_RATE_LIMIT_PER_MINUTE=0
NEWSLETTER_RATE_LIMIT_PER_HOUR=1000
NEWSLETTER_RATE_LIMIT_PER_DAY=10000
Keeping PER_MINUTE=0 and using only hourly/daily is a common choice for large campaigns to avoid many small queue delays.
Queue / worker: ensure the worker --timeout stays a few seconds below your database queue retry_after (see config/queue.php, DB_QUEUE_RETRY_AFTER) so jobs are not processed twice.
Check current counters:
php artisan newsletter:rate-limits
REST API
The application exposes a full REST API authenticated via Laravel Sanctum personal access tokens.
Authentication
- Go to the admin panel user menu > API tokens (or navigate to
/api-tokens) - Create a token with the API ability enabled
- Use the token in the
Authorizationheader:
Authorization: Bearer <your-token>
Endpoints
All endpoints are prefixed with /api and require a valid Bearer token with the api ability.
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/user |
Authenticated user info |
GET |
/api/reports/newsletter |
Newsletter report (filterable) |
GET |
/api/tags |
List all tags |
POST |
/api/tags |
Create a tag |
GET |
/api/tags/{tag} |
Show a tag |
PUT |
/api/tags/{tag} |
Update a tag |
DELETE |
/api/tags/{tag} |
Delete a tag |
GET |
/api/subscribers |
List subscribers |
POST |
/api/subscribers |
Create a subscriber |
GET |
/api/subscribers/{subscriber} |
Show a subscriber |
PUT |
/api/subscribers/{subscriber} |
Update a subscriber |
DELETE |
/api/subscribers/{subscriber} |
Delete a subscriber |
GET |
/api/templates |
List templates |
POST |
/api/templates |
Create a template |
GET |
/api/templates/{template} |
Show a template |
PUT |
/api/templates/{template} |
Update a template |
DELETE |
/api/templates/{template} |
Delete a template |
GET |
/api/campaigns |
List campaigns |
POST |
/api/campaigns |
Create a campaign |
GET |
/api/campaigns/{campaign} |
Show a campaign |
PUT |
/api/campaigns/{campaign} |
Update a campaign |
DELETE |
/api/campaigns/{campaign} |
Delete a campaign |
GET |
/api/campaigns/{campaign}/messages |
List messages in a campaign |
POST |
/api/campaigns/{campaign}/messages |
Create a message |
GET |
/api/campaigns/{campaign}/messages/{message} |
Show a message |
PUT |
/api/campaigns/{campaign}/messages/{message} |
Update a message |
DELETE |
/api/campaigns/{campaign}/messages/{message} |
Delete a message |
OpenAPI Documentation
Interactive Swagger UI is available at /api/documentation. Generate or update the spec with:
php artisan l5-swagger:generate
MCP Server (AI Integrations)
The application includes a Model Context Protocol (MCP) server that allows AI clients (Cursor, Claude Code, Windsurf, etc.) to interact with your newsletter data.
Endpoint
/mcp/newsletter
Authenticated with a Sanctum Bearer token that has the mcp ability.
Available Tools
| Tool | Description |
|---|---|
list-campaigns |
Lists campaigns (all campaigns for managers/administrators; editors see their own) |
newsletter-report |
Delivery report with summary, per-message stats, and daily timeseries |
send-history-analysis |
Highlights and trends from recent send history |
subscriber-insights |
Audience breakdown by tags and statuses |
generate-email-template-html |
Generates responsive HTML email template from a description |
create-newsletter-message |
Creates a draft or ready message inside a campaign |
Prompt
The server ships with a newsletter-assistant prompt — a reusable skill template that guides AI assistants through campaign planning, report interpretation, content drafting, and message creation.
Setup in Your AI Client
- Create a token in the admin panel with the MCP ability
- Configure your AI client to connect to the MCP endpoint with the token as Bearer auth
- Debug locally with:
php artisan mcp:inspector mcp/newsletter
VS Code / Cursor mcp.json example (HTTP)
Point the URL at your app’s origin plus /mcp/newsletter, and send the Sanctum token in the Authorization header:
{
"mcpServers": {
"newsletter": {
"url": "https://your-domain.example/mcp/newsletter",
"headers": {
"Authorization": "Bearer YOUR_SANCTUM_TOKEN"
}
}
}
}
Replace your-domain.example with your deployment host (for local development, something like http://127.0.0.1:8000/mcp/newsletter). Replace YOUR_SANCTUM_TOKEN with the plaintext token string from the admin panel (treat it like a password).
Example requests
You can phrase tasks in natural English; the assistant maps them to MCP tools. Examples:
- Campaigns: “List all newsletter campaigns.” / “What campaigns do we have?”
- Delivery stats: “Give me a newsletter delivery report from 2026-01-01 to 2026-01-31.” / “Show sends, opens, clicks, and bounces for the last 30 days.”
- Scoped report: “Report for the campaign with id … between 2026-01-01 and 2026-01-31.”
- Narrative summary: “Summarize send history and highlights for the last quarter.”
- Audience: “How many subscribers do we have by status? Which tags have the most subscribers?”
- HTML: “Generate a responsive HTML email template for a product launch: hero, short intro, three feature bullets, primary CTA button.”
- New message: “Create a draft message in the given campaign id, using the given template id, subject Weekly digest, HTML body …, and the listed tag ids.”
For send statistics and campaign listing, use a token belonging to a Manager or Administrator if your organization splits campaign ownership across users; those roles see all campaigns in reports (same idea as the admin panel).
Testing Tags
Tags can be marked as testing (is_testing flag) in the Filament admin panel. When a message targets recipients only through testing tags:
- Sends are excluded from dashboard statistics (emails sent, opens, clicks, bounces, charts)
- After the send completes, per-recipient send rows and related bounces are removed from the database
- Testing tags and normal tags cannot be mixed on the same message
This allows safe end-to-end testing of the sending pipeline without polluting production metrics.
Multilingual Support
The admin panel supports six languages: Italian, English, German, French, Spanish, and Portuguese.
- Logged-in users can choose their language from the Profile page
- Before login, the panel detects the browser
Accept-Languageheader and uses the closest supported language (defaults to English) - New users automatically inherit the browser language on account creation
Public Routes
The following routes are available for public use:
| Route | Method | Description |
|---|---|---|
/subscribe |
GET | Subscription form |
/subscribe |
POST | Process subscription |
/subscribe/confirm/{token} |
GET | Confirm subscription (double opt-in) |
/unsubscribe/{subscriber} |
GET | Unsubscribe form |
/unsubscribe/{subscriber}/confirm |
POST | Confirm unsubscribe |
Scheduled Tasks
Add the Laravel scheduler to your crontab:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
| Task | Schedule | Description |
|---|---|---|
newsletter:send-scheduled |
Every minute | Sends messages with scheduled date in the past |
newsletter:process-bounces |
Every 15 minutes | Processes bounced emails via IMAP |
backup:run |
Daily at 03:00 | Runs application backup |
backup:clean |
Daily at 04:00 | Cleans old backups |
Artisan Commands
| Command | Description |
|---|---|
newsletter:seed-data |
Populate database with sample subscribers, campaigns, and messages |
newsletter:send-scheduled |
Manually trigger scheduled message sending |
newsletter:process-pending |
Process pending emails in the queue |
newsletter:process-bounces |
Process bounced emails from IMAP |
newsletter:rate-limits |
Display current rate limit status |
l5-swagger:generate |
Generate or update the OpenAPI specification |
mcp:inspector mcp/newsletter |
Debug the MCP server locally |
Take it to production — cipi.sh
Once your app is ready, deploy it to any Ubuntu VPS with cipi.sh — an open-source CLI built exclusively for Laravel.
- Full app isolation — own Linux user, PHP-FPM pool & database per app
- Zero-downtime deploys with instant rollback via Deployer
- Let's Encrypt SSL, Fail2ban, UFW firewall — all automated
- Multi-PHP (7.4 → 8.5), queue workers, S3 backups, auto-deploy webhooks
- AI Agent ready — any AI with SSH access can deploy & manage your server
wget -O - https://raw.githubusercontent.com/andreapollastri/cipi/refs/heads/latest/install.sh | bash
→ Learn more at cipi.sh
Troubleshooting
Emails not sending
- Ensure the queue worker is running:
./start-worker.shorphp artisan queue:work - Manually process pending:
php artisan newsletter:process-pending - Check the jobs table:
php artisan tinker --execute="DB::table('jobs')->count()"
Test email delivery
php artisan tinker --execute="Mail::raw('Test', fn(\$m) => \$m->to('[email protected]'))"
Verify rate limits
php artisan newsletter:rate-limits
Frontend changes not visible
Run npm run build or npm run dev to compile assets.
API issues
- Verify the token is valid: check the API tokens page in the admin panel
- Ensure the token has the correct ability (
apifor REST endpoints,mcpfor the MCP server) - Check the OpenAPI docs at
/api/documentationfor request/response format
License
MIT
Credits
Created by Andrea Pollastri
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found