ekandreas / filament-resonator
A Filament plugin for managing email inbox with Resend and AI-powered features via Prism
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/ekandreas/filament-resonator
Requires
- php: ^8.4
- filament/filament: ^4.0
- illuminate/contracts: ^12.0
- prism-php/prism: ^1.0
- saloonphp/saloon: ^3.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.1
- orchestra/testbench: ^10.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.3
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
This package is auto-updated.
Last update: 2026-01-03 14:13:00 UTC
README
A powerful email inbox plugin for Filament 4 with Resend integration and AI-powered features via Prism.
Features
- ๐ง Full Email Inbox - Send, receive, and manage emails directly in Filament
- ๐งต Thread Grouping - Automatic conversation threading via headers
- ๐ Folder Management - Inbox, Sent, Archive, Spam, Trash + custom folders
- ๐ค AI Spam Detection - Automatic spam classification using Prism + LLM
- ๐ค Contact Enrichment - Extract contact info from emails via AI
- ๐ Reply Snippets - Pre-defined templates for quick responses
- ๐ Auto Sync - Scheduled syncing via artisan command
- ๐ Multilingual - 9 languages included (EN, SV, DE, FR, ES, NB, FI, DA, PT)
Architecture Overview
graph TB
subgraph "Filament Panel"
IR[InboxResource]
FR[FolderResource]
SR[SnippetResource]
SFR[SpamFilterResource]
end
subgraph "Core"
RP[ResonatorPlugin]
RSP[ResonatorServiceProvider]
end
subgraph "Actions"
SE[SyncEmails]
SR2[SendReply]
CO[CleanupOldMessages]
end
subgraph "Jobs"
DS[DetectSpam]
EC[EnrichContact]
end
subgraph "External Services"
RESEND[(Resend API)]
PRISM[Prism]
LLM[(OpenAI / Anthropic / Ollama)]
end
RP --> IR
RP --> FR
RP --> SR
RP --> SFR
IR --> SE
IR --> SR2
SE --> RESEND
SR2 --> RESEND
CO --> RESEND
DS --> PRISM
EC --> PRISM
PRISM --> LLM
Loading
Technology Stack
graph LR
subgraph "Frontend"
F[Filament 4]
B[Blade Views]
L[Livewire]
end
subgraph "Backend"
LA[Laravel 12]
SP[Spatie Package Tools]
end
subgraph "Email"
RE[Resend API]
SA[Saloon HTTP]
end
subgraph "AI Layer"
PR[Prism PHP]
OA[OpenAI]
AN[Anthropic]
OL[Ollama]
end
F --> LA
B --> F
L --> F
LA --> SP
LA --> SA
SA --> RE
LA --> PR
PR --> OA
PR --> AN
PR --> OL
Loading
Data Model
erDiagram
ResonatorFolder ||--o{ ResonatorThread : contains
ResonatorThread ||--o{ ResonatorEmail : contains
ResonatorThread }o--o{ ResonatorContact : has
ResonatorEmail ||--o{ ResonatorAttachment : has
User ||--o{ ResonatorThread : handles
User ||--o{ ResonatorSpamFilter : creates
ResonatorFolder {
bigint id PK
string name
string slug UK
string icon
string color
boolean is_system
integer sort_order
}
ResonatorThread {
bigint id PK
bigint folder_id FK
string subject
string participant_email
string participant_name
boolean is_starred
boolean is_read
datetime last_message_at
bigint handled_by FK
datetime handled_at
}
ResonatorEmail {
bigint id PK
bigint thread_id FK
string resend_id UK
string message_id
string in_reply_to
boolean is_inbound
string from_email
string from_name
json to
string subject
longtext html
longtext text
datetime sent_at
}
ResonatorAttachment {
bigint id PK
bigint email_id FK
string resend_id
string filename
string content_type
bigint size
}
ResonatorContact {
bigint id PK
string email UK
string name
string phone
string company
string unsubscribe_token UK
datetime unsubscribed_at
}
ResonatorSnippet {
bigint id PK
string name
string shortcut UK
string subject
longtext body
integer sort_order
boolean is_active
}
ResonatorSpamFilter {
bigint id PK
string email UK
text reason
bigint created_by FK
}
Loading
Email Sync Flow
sequenceDiagram
participant Scheduler
participant SyncEmails
participant Resend
participant Database
participant DetectSpam
participant Prism
participant LLM
Scheduler->>SyncEmails: resonator:sync
SyncEmails->>Resend: GET /emails/receiving
Resend-->>SyncEmails: List of emails
loop For each email
SyncEmails->>Resend: GET /emails/receiving/{id}
Resend-->>SyncEmails: Email details
SyncEmails->>SyncEmails: Check spam filter
SyncEmails->>SyncEmails: Find/create thread
SyncEmails->>Database: Create ResonatorEmail
SyncEmails->>Database: Create ResonatorAttachment(s)
SyncEmails->>DetectSpam: Dispatch job (5s delay)
end
DetectSpam->>Prism: Structured prompt
Prism->>LLM: Analyze email content
LLM-->>Prism: JSON response
Prism-->>DetectSpam: {is_spam, reason}
alt is_spam = true
DetectSpam->>Database: Move thread to spam folder
end
SyncEmails-->>Scheduler: {synced, skipped, spam, errors}
Loading
Reply Flow
sequenceDiagram
participant User
participant ViewThread
participant SendReply
participant Mail
participant Resend
participant Database
User->>ViewThread: Click Reply
User->>ViewThread: Select snippet (optional)
User->>ViewThread: Write message
User->>ViewThread: Submit
ViewThread->>SendReply: execute(thread, body)
SendReply->>SendReply: Build signature
SendReply->>SendReply: Set In-Reply-To headers
SendReply->>Mail: Send via Laravel Mail
Mail->>Resend: POST /emails
Resend-->>Mail: {id, status}
SendReply->>Database: Create ResonatorEmail (is_inbound=false)
SendReply->>Database: Move thread to Sent folder
SendReply->>Database: Mark as handled
SendReply-->>ViewThread: Success
ViewThread-->>User: Notification + Redirect
Loading
Installation
Step 1: Install via Composer
composer require ekandreas/filament-resonator
Step 2: Publish and run migrations
php artisan vendor:publish --tag="resonator-migrations"
php artisan migrate
Step 3: Publish config (optional)
php artisan vendor:publish --tag="resonator-config"
Step 4: Configure Prism
Resonator uses Prism for AI features. Configure your preferred provider in config/prism.php:
// config/prism.php return [ 'providers' => [ 'openai' => [ 'api_key' => env('OPENAI_API_KEY'), ], // Or use Anthropic, Ollama, etc. ], ];
Step 5: Register the plugin
In your Filament Panel Provider:
use EkAndreas\Resonator\ResonatorPlugin; public function panel(Panel $panel): Panel { return $panel // ... ->plugins([ ResonatorPlugin::make(), ]); }
Configuration
Environment Variables
# Required - Resend RESEND_KEY=re_xxxxxxxxxxxx # Required for AI features - Choose one provider OPENAI_API_KEY=sk-xxxxxxxxxxxx # or ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxx # Optional - Mail settings RESONATOR_FROM_ADDRESS=hello@example.com RESONATOR_FROM_NAME="My App" # Optional - AI settings RESONATOR_AI_ENABLED=true RESONATOR_AI_PROVIDER=openai RESONATOR_AI_MODEL=gpt-4o-mini # Optional - Features RESONATOR_SPAM_DETECTION=true RESONATOR_CONTACT_ENRICHMENT=true RESONATOR_CLEANUP_ENABLED=true RESONATOR_CLEANUP_DAYS=30
Config File
// config/resonator.php return [ 'resend' => [ 'key' => env('RESEND_KEY'), ], 'mail' => [ 'from_address' => env('RESONATOR_FROM_ADDRESS'), 'from_name' => env('RESONATOR_FROM_NAME'), ], 'ai' => [ 'enabled' => env('RESONATOR_AI_ENABLED', true), 'provider' => env('RESONATOR_AI_PROVIDER', 'openai'), 'model' => env('RESONATOR_AI_MODEL', 'gpt-4o-mini'), ], 'spam_detection' => [ 'enabled' => env('RESONATOR_SPAM_DETECTION', true), 'delay_seconds' => 5, ], 'contact_enrichment' => [ 'enabled' => env('RESONATOR_CONTACT_ENRICHMENT', true), 'max_emails_to_analyze' => 3, 'max_text_length' => 3000, ], 'navigation' => [ 'group' => 'Resonator', 'sort' => 100, ], 'pagination' => [ 'default' => 25, 'options' => [25, 50, 100], ], ];
Prism AI Integration
Resonator leverages Prism's structured output feature for reliable AI responses:
graph TD
subgraph "Prism Structured Output"
A[Email Content] --> B[System Prompt]
B --> C[ObjectSchema]
C --> D{Provider}
D --> E[OpenAI]
D --> F[Anthropic]
D --> G[Ollama]
E --> H[JSON Response]
F --> H
G --> H
H --> I[Validated Data]
end
Loading
Spam Detection Schema
$schema = new ObjectSchema( name: 'spam_detection', properties: [ new BooleanSchema('is_spam'), new StringSchema('reason'), ], requiredFields: ['is_spam'] );
Contact Enrichment Schema
$schema = new ObjectSchema( name: 'contact_info', properties: [ new StringSchema('name'), new StringSchema('phone'), new StringSchema('company'), ] );
Supported Prism Providers
| Provider | Model Examples | Config |
|---|---|---|
| OpenAI | gpt-4o-mini, gpt-4o |
OPENAI_API_KEY |
| Anthropic | claude-3-haiku, claude-3-sonnet |
ANTHROPIC_API_KEY |
| Ollama | llama3, mistral |
Local installation |
Plugin Options
ResonatorPlugin::make() ->folders(true) // Enable folder management ->snippets(true) // Enable reply snippets ->spamFilters(true) // Enable spam filter management
Scheduled Syncing
Add to your routes/console.php or scheduler:
use Illuminate\Support\Facades\Schedule; Schedule::command('resonator:sync')->everyFiveMinutes();
Or in app/Console/Kernel.php:
protected function schedule(Schedule $schedule): void { $schedule->command('resonator:sync')->everyFiveMinutes(); }
Command Reference
# Sync emails and cleanup old messages php artisan resonator:sync # Sync without cleanup php artisan resonator:sync --no-cleanup # Custom cleanup period php artisan resonator:sync --cleanup-days=60
Navigation Structure
graph LR
subgraph "Resonator Menu Group"
A[๐ฅ Inbox] --> A1[View Threads]
A --> A2[Compose]
A --> A3[Sync]
B[๐ Folders] --> B1[Manage Folders]
C[๐ Snippets] --> C1[Manage Templates]
D[๐ก๏ธ Spam Filters] --> D1[Manage Blocked]
end
Loading
System Folders
The following folders are created automatically:
| Folder | Slug | Icon | Purpose |
|---|---|---|---|
| Inbox | inbox |
๐ฅ | Incoming messages |
| Sent | sent |
๐ค | Outgoing messages |
| Archive | archive |
๐ฆ | Archived threads |
| Spam | spam |
๐ก๏ธ | Spam messages |
| Trash | trash |
๐๏ธ | Deleted messages |
AI Features
Spam Detection Flow
flowchart TD
A[New Email Received] --> B{Is Inbound?}
B -->|No| END[Skip]
B -->|Yes| C[Queue DetectSpam Job]
C --> D[Wait 5 seconds]
D --> E[Build Prompt]
E --> F[Prism Structured Call]
F --> G[LLM Analysis]
G --> H{AI Response}
H -->|is_spam: true| I[Move to Spam Folder]
H -->|is_spam: false| J[Keep in Inbox]
I --> K[Log Result]
J --> K
Loading
Contact Enrichment
flowchart TD
A[Thread Created] --> B[Queue EnrichContact Job]
B --> C{Contact Complete?}
C -->|Yes| END[Skip]
C -->|No| D[Collect Last 3 Emails]
D --> E[Limit Text to 3000 chars]
E --> F[Prism Structured Call]
F --> G[LLM Extraction]
G --> H[Extract: name, phone, company]
H --> I{Found New Data?}
I -->|Yes| J[Update Contact]
I -->|No| END2[Skip]
Loading
Thread Matching Logic
flowchart TD
A[New Email] --> B{Has In-Reply-To?}
B -->|Yes| C[Find by Message-ID]
C --> D{Found?}
D -->|Yes| E[Add to Existing Thread]
D -->|No| F{Match Subject + Sender?}
B -->|No| F
F -->|Yes| G[Within 30 days?]
G -->|Yes| E
G -->|No| H[Create New Thread]
F -->|No| H
Loading
Translations
Resonator includes translations for the following languages:
| Language | Code | File |
|---|---|---|
| English | en |
resources/lang/en/resonator.php |
| Swedish | sv |
resources/lang/sv/resonator.php |
| German | de |
resources/lang/de/resonator.php |
| French | fr |
resources/lang/fr/resonator.php |
| Spanish | es |
resources/lang/es/resonator.php |
| Norwegian | nb |
resources/lang/nb/resonator.php |
| Finnish | fi |
resources/lang/fi/resonator.php |
| Danish | da |
resources/lang/da/resonator.php |
| Portuguese | pt |
resources/lang/pt/resonator.php |
To add more languages:
php artisan vendor:publish --tag="resonator-translations"
Then create your translation file in lang/vendor/resonator/{locale}/resonator.php.
Extending
Custom Folder Types
use EkAndreas\Resonator\Models\ResonatorFolder; ResonatorFolder::create([ 'name' => 'VIP', 'slug' => 'vip', 'icon' => 'heroicon-o-star', 'color' => 'warning', 'is_system' => false, ]);
Custom Snippets
use EkAndreas\Resonator\Models\ResonatorSnippet; ResonatorSnippet::create([ 'name' => 'Welcome Message', 'shortcut' => 'welcome', 'subject' => 'Welcome to Our Service', 'body' => '<p>Thank you for reaching out...</p>', 'is_active' => true, ]);
Listening to Events
// In a service provider use EkAndreas\Resonator\Models\ResonatorEmail; ResonatorEmail::created(function ($email) { if ($email->is_inbound) { // Notify team, trigger webhooks, etc. } });
File Structure
src/
โโโ Actions/
โ โโโ CleanupOldMessages.php
โ โโโ SendReply.php
โ โโโ SyncEmails.php
โโโ Commands/
โ โโโ SyncInboxCommand.php
โโโ Filament/
โ โโโ Resources/
โ โโโ FolderResource.php
โ โโโ InboxResource.php
โ โโโ SnippetResource.php
โ โโโ SpamFilterResource.php
โโโ Http/
โ โโโ Integrations/
โ โโโ Resend/
โ โโโ ResendConnector.php
โ โโโ Requests/
โโโ Jobs/
โ โโโ DetectSpam.php
โ โโโ EnrichContact.php
โโโ Models/
โ โโโ ResonatorAttachment.php
โ โโโ ResonatorContact.php
โ โโโ ResonatorEmail.php
โ โโโ ResonatorFolder.php
โ โโโ ResonatorSnippet.php
โ โโโ ResonatorSpamFilter.php
โ โโโ ResonatorThread.php
โโโ ResonatorPlugin.php
โโโ ResonatorServiceProvider.php
Testing
composer test
Requirements
- PHP 8.4+
- Laravel 12.x
- Filament 4.x
- Resend account with API key
- LLM API key (OpenAI, Anthropic, or local Ollama)
Dependencies
| Package | Version | Description |
|---|---|---|
php |
^8.4 | PHP 8.4 or higher |
filament/filament |
^4.0 | Filament admin panel (includes Livewire 3) |
illuminate/contracts |
^12.0 | Laravel 12 contracts |
prism-php/prism |
^1.0 | AI integration layer |
saloonphp/saloon |
^3.0 | HTTP client for Resend API |
spatie/laravel-package-tools |
^1.16 | Package development utilities |
graph TD
A[filament-resonator] --> B[filament/filament ^4.0]
A --> C[spatie/laravel-package-tools ^1.16]
A --> D[saloonphp/saloon ^3.0]
A --> E[prism-php/prism ^1.0]
B --> F[Livewire 3]
B --> G[Laravel 12]
E --> H[OpenAI]
E --> I[Anthropic]
E --> J[Ollama]
Loading
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security
If you discover any security related issues, please email security@elseif.se instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.