Per gli sviluppatori

Costruisci plugin. Non workaround.

AcelleMail è una piattaforma di email marketing Laravel 11+ che viene distribuita con il sorgente PHP completo non cifrato — e un Hook system tipizzato che permette ai tuoi plugin di aggiungere sending driver, gateway di pagamento, AI, UI custom, persino REST API. Senza fare il fork del core.

Plugin reali in produzione oggi

acelle/ai athena/evs rencontru/postal acelle/console
myvendor/loyalty/ PLUGIN SOURCE composer.json 240 B routes.php 1.2 KB src/ ServiceProvider.php entry Controllers/ Models/ database/migrations/ resources/ views/ lang/ index.json auto $ php artisan plugin:init … HOOK SYSTEM no core touches ACELLEMAIL Laravel 11+ · PHP 8.3+ layout.head.assets layout.body.close admin.sidebar.groups register_sending_* page.{ctrl}.{slot} customer_added sidebar-menu-items dispatch_*_job + many more…

Perché gli sviluppatori scelgono AcelleMail

Costruito sul framework che già conosci.
Esteso tramite pattern che già usi.

PHP / Laravel open source

Il sorgente PHP completo non cifrato viene distribuito con ogni licenza. Modifica qualsiasi classe, fai override di qualsiasi service, fai il fork nel tuo namespace — il tuo codice, le tue regole. Costruito su Laravel 11+ così il framework che già conosci si occupa del grosso del lavoro.

$ grep -r "protected function" vendor/acelle/

Architettura a plugin

Metti una cartella in stile Composer sotto storage/app/plugins/<vendor>/<name>/ e l'app la autoloada. Il ServiceProvider inietta route, view, migration, hook — attiva, disattiva, elimina in modo pulito.

$ php artisan plugin:init myvendor/loyalty

REST API con autenticazione a token

Endpoint CRUD per campagne, liste, iscritti, template, automation. Eventi webhook per ogni accadimento a livello di dominio. Drop-in per frontend SaaS, app mobile o altri service Laravel. La stessa API che usano i plugin è la stessa API che usano i client esterni — niente endpoint di seconda classe.

GET /api/v1/campaigns · POST /api/v1/lists

Self-hosted sulla tua infra

Il tuo server, il tuo DB, i dati dei tuoi iscritti. Nessun vendor lock-in. Paga una volta la licenza; paga solo il costo SMTP sottostante (es. Amazon SES a $0,10/1K). Deploya ovunque giri PHP — bare metal, Kubernetes, Forge, Laravel Vapor. Scala come scala il tuo stack.

· PHP 8.3+ · MySQL / MariaDB · Redis (optional)

Cosa puoi costruire con i plugin

14 superfici di estensione.
Ognuna con un esempio reale in produzione oggi.

Un plugin è un pacchetto Laravel autocontenuto che vive su disco, ha il proprio namespace, le proprie tabelle di database, route, view, controller, model — e si integra con il core attraverso un Hook system tipizzato invece di hack a base di include.

Driver e integrazioni · 4

Sending server / driver REGISTRY
register_sending_server_driver
rencontru/postal — driver Postal MTA come plugin drop-in singolo
Verifica email / deliverability REGISTRY
REGISTRY + FILTER
athena/evs — sottosistema di verifica con UI admin
Gateway di pagamento REGISTRY
REGISTRY
Stripe / PayPal / Braintree / Paystack / Razorpay / Coinbase integrati mostrano il pattern
AI / chatbot / assistenti REGISTRY
REGISTRY + EVENT
acelle/ai — chatbox + sparkle + observability

UI e pagine · 5

Iniezione di UI custom REGISTRY
layout.head.assets / layout.body.before_close / admin.sidebar.groups
Chatbox + sparkle popover di acelle/ai
Slot di contenuto a livello di pagina REGISTRY
page.{ctrl}.{action}.{slot}
page.maillist.show.body, page.campaign.index.sidebar
Pagine admin ROUTE
Laravel routes
/rui/admin/ai-usage, /rui/admin/ai-audit, /rui/admin/ai-conversations
Pagine rivolte al customer ROUTE
Laravel routes
/plugins/acelle/ai/dashboard
REST API ROUTE
Routes + api.access_token
/api/v1/ai/* in acelle/ai

Dati e ciclo di vita · 2

Model Eloquent custom + tabelle DB BEHAVIOR
Plugin-isolated migrations
acelle/ai include 8 model / 12 migration, nomi di tabella con prefisso vendor
Traduzioni (18 locali) REGISTRY
add_translation_file
acelle/ai include 162 file di lang (18 × 9)

Comportamento e flusso · 3

Listener webhook / eventi di dominio EVENT
Hook::on(…)
customer_added, plan_changed, subscription_terminated
Override di comportamento BEHAVIOR
Hook::set / setIfEmpty / perform
dispatch_list_import_job — sostituisce completamente la logica di import
Catene di filter FILTER
Hook::modify / filter
sidebar-menu-items, mutazione del contenuto pre-invio, URL di redirect

Un singolo plugin può mescolare qualsiasi di queste superfici — acelle/ai ne usa 7 su 14 in un solo pacchetto.

L'Hook system

Quattro pattern di estensione tipizzati. Nessun override a sorpresa. Nessun conflitto silenzioso.

Il core non importa mai codice dei plugin — dichiara solo extension point. I plugin ascoltano e reagiscono. Quattro pattern, ciascuno con un ruolo chiaro. I conflitti lanciano un'eccezione immediatamente.

1

REGISTRY add() + collect()

Il plugin contribuisce elementi a una lista. Il core chiede "chi ha un sending driver?" e il tuo plugin risponde "io".


Hook::add('register_sending_server_driver', fn () => [
    'type'   => 'myvendor-foo',
    'driver' => \MyVendor\Foo\Driver::class,
]);


$drivers = Hook::collect('register_sending_server_driver');
2

EVENT on() + fire()

Il plugin reagisce a qualcosa che accade. I valori di ritorno vengono scartati.


Hook::on('customer_added', function ($customer) {
    LoyaltyPoints::award($customer, 100, 'welcome');
});


Hook::fire('customer_added', [$customer]);
3

BEHAVIOR set() + perform()

Il plugin sostituisce completamente un pezzo della logica del core. Solo un plugin può rivendicare un dato behavior — i conflitti lanciano un'eccezione immediatamente.


Hook::set('dispatch_list_import_job',
    fn ($list, $f) => new MyFasterImportJob($list, $f));


Hook::setIfEmpty('dispatch_list_import_job',
    fn ($list, $f) => new DefaultImportJob($list, $f));
$job = Hook::perform('dispatch_list_import_job', [$list, $f]);
dispatch($job);
4

FILTER modify() + filter()

Il plugin trasforma un valore attraverso una catena di callback. Ogni callback riceve il valore corrente, restituisce il valore modificato.


Hook::modify('sidebar-menu-items', function (array $items) {
    $items[] = [
        'label' => 'Loyalty',
        'url'   => route('lp.dashboard'),
    ];
    return $items;
});


$menu = Hook::filter('sidebar-menu-items', $defaultMenu);

Hello World in 5 minuti

Un plugin funzionante da zero in otto comandi.

Lo scaffold crea tutto — metadata Composer, ServiceProvider, model di esempio, migration di esempio, route di esempio, view di esempio. Da lì è tuo da far crescere.

  1. 1

    Scaffold del plugin

    Crea il layout standard di cartelle + una riga DB inattiva.

    bash
    $ php artisan plugin:init myvendor/loyalty
      ✓ Created storage/app/plugins/myvendor/loyalty/
      ✓ DB row inserted  (status: inactive)
      ✓ index.json + ServiceProvider autoloaded
  2. 2

    Modifica composer.json

    Comunica a Composer il tuo namespace e il ServiceProvider.

    json
    {
      "name": "myvendor/loyalty",
      "description": "Award points on signup",
      "version": "1.0.0",
      "autoload":  { "psr-4": { "MyVendor\\Loyalty\\": "src/" } },
      "extra":     { "laravel": { "providers": [
        "MyVendor\\Loyalty\\ServiceProvider"
      ] } }
    }
  3. 3

    Scrivi una migration

    Tabella isolata al plugin, nome con prefisso vendor. Gira sull'attivazione, fa rollback sull'eliminazione.

    php
    Schema::create('myvendor_loyalty_accounts', function (Blueprint $t) {
        $t->id();
        $t->foreignId('customer_id')->constrained()->cascadeOnDelete();
        $t->integer('points')->default(0);
        $t->timestamps();
    });
  4. 4

    Definisci un model

    Model Eloquent standard nel tuo namespace.

    php
    namespace MyVendor\Loyalty\Models;
    
    use Illuminate\Database\Eloquent\Model;
    
    class Account extends Model
    {
        protected $table    = 'myvendor_loyalty_accounts';
        protected $fillable = ['customer_id', 'points'];
    }
  5. 5

    Aggiungi un controller e una view

    Controller Laravel semplice — il namespace della view è il nome del tuo plugin.

    php
    namespace MyVendor\Loyalty\Controllers;
    
    use Acelle\Http\Controllers\Controller;
    
    class DashboardController extends Controller
    {
        public function index()
        {
            return view('loyalty::dashboard', [
                'accounts' => \MyVendor\Loyalty\Models\Account::orderByDesc('points')->take(10)->get(),
            ]);
        }
    }
  6. 6

    Dichiara le route

    Lo stesso Route::group che già usi. Caricato da ServiceProvider::boot().

    php
    Route::group([
        'middleware' => ['web', 'auth'],
        'namespace'  => '\MyVendor\Loyalty\Controllers',
        'prefix'     => 'plugins/myvendor/loyalty',
    ], function () {
        Route::get('/',          'DashboardController@index')->name('lp.dashboard');
        Route::get('/{account}', 'DashboardController@show');
    });
  7. 7

    Collega tutto in ServiceProvider::boot()

    Carica view + route; aggancia activate_plugin_… per migrare all'attivazione.

    php
    public function boot(): void
    {
        $this->loadViewsFrom (__DIR__.'/../resources/views', 'loyalty');
        $this->loadRoutesFrom(__DIR__.'/../routes.php');
    
        Hook::on('activate_plugin_myvendor/loyalty', fn () =>
            \Artisan::call('migrate', [
                '--path'  => 'storage/app/plugins/myvendor/loyalty/database/migrations',
                '--force' => true,
            ])
        );
    
        Hook::on('customer_added', fn ($customer) =>
            Models\Account::create(['customer_id' => $customer->id, 'points' => 100])
        );
    }
  8. 8

    Attiva dall'admin

    Vai su /rui/admin/plugins. Le migration girano in automatico. Il plugin vive al suo prefisso.

    bash
    ✓ activated  myvendor/loyalty  v1.0.0
      → migrations: 1 ran (myvendor_loyalty_accounts)
      → routes:     2 registered under /plugins/myvendor/loyalty
      → hooks:      2 listening (activate, customer_added)
      → status:     active
    
    → visit /plugins/myvendor/loyalty/  ← live

Ora hai un plugin funzionante. Aggiungi quanti model, controller, hook richiede la tua feature. I test vivono in tests/; eseguili con php artisan test --testsuite='Plugin: myvendor/loyalty'. Trova il contratto canonico nella knowledge base.

Ciclo di vita del plugin

Quattro stati. Transizioni prevedibili. Nessun mistero sul "è girato o no?".

Ogni plugin vive in esattamente uno di quattro stati. Lo stato in cui sei determina quali hook scattano, quali migration sono state eseguite e cosa succede alla prossima transizione. Source-grounded contro docs/plugin/SOURCE_OF_TRUTH.md.

STATE 01 register (inactive) Cartella plugin scoperta. index.json + riga DB esistono. Gli hook NON scattano. STATE 02 active Tutti gli hook vivi. Route montate. Le migration sono state eseguite. activate_plugin_… scattato una volta. STATE 03 inactive (in pausa) Cartella ancora sul disco. Hook in pausa. Route smontate. Tabelle DB intatte. STATE 04 deleted (sparito) Cartella rimossa. Migration in rollback se $keepData = false. Riga DB rimossa. activate le migration girano deactivate dati conservati remove $keepData? re-activate l'hook activate NON gira di nuovo
Register · inactive

Scoperto, non in esecuzione

La cartella plugin esiste, index.json indicizzato, la riga DB dice inactive. Il register() del ServiceProvider è girato, ma gli hook in boot() sono bloccati fino a quando non clicchi Activate.

Active

Vivo, hook che scattano

La prima attivazione fa scattare activate_plugin_<name> una volta — è qui che girano le migration. Dopo di che tutti gli hook REGISTRY / EVENT / FILTER / BEHAVIOR sono vivi fino alla disattivazione.

Inactive · in pausa

In pausa, dati intatti

Le route si smontano, gli hook si bloccano, ma la cartella + le tabelle DB rimangono. Il re-activate non rifa girare le migration né l'hook activate — sicuro da toggleare in produzione.

Deleted

Rimosso in modo pulito

Cartella rimossa, riga DB sparita. Se $keepData = false, le migration del plugin fanno rollback — le tabelle con prefisso vendor cadono. Le tabelle del core non vengono mai toccate.

Vetrina di un plugin reale

acelle/ai — un sottosistema AI completo in una singola cartella plugin.

Il plugin acelle/ai distribuisce un layer di assistente AI completo: chatbox agent su ogni pagina, ✨ sparkle di riscrittura testo sui campi rich-text, persone coach KB-grounded (Deliverability, Segments, Campaigns, Forms) e una superficie di observability admin su 5 route. Si monta tramite 3 layout hook. Zero modifiche al core.

Plugin acelle/ai in azione — bolla chatbox AI AcelleMail fluttuante con il popover sparkle ✨ per riscrittura con un click, più il gruppo della sidebar admin del plugin renderizzato dentro la UI di AcelleMail

Cosa include

  • Chatbox fluttuante — modalità supporto semplice + modalità agent opt-in che chiama tool
  • Sparkle popover — riscrittura / espansione / semplificazione con un click su ogni campo rich-text
  • Coach personas — helper LLM consapevoli del dominio, limitati per schermata
  • Observability admin — usage, audit, conversations, feedback, self-improve
  • Flessibilità del motore — BYO OpenAI, Anthropic o Ollama locale
  • Landing page del plugin a /plugins/acelle/ai/dashboard

In numeri

8
Model Eloquent
12
Migration
60+
Template Blade
100+
Test Pest
18 × 9
Locali × file di lang
~35
File CSS + JS

Come si monta — 3 hook

acelle/ai plugin → CSS / JS assets Hook::add( 'layout.head.assets', fn()=>...); → Chatbox bubble Hook::add( 'layout.body.before_close' ,fn()=>...); → AI sidebar group Hook::add( 'admin.sidebar.groups', fn()=>...); Self-contained. AcelleMail core <head> + acelle-ai-chatbox.css </body> (just before) + <div class="ai-chatbox"> Admin sidebar AI · Settings AI · Usage AI · Conversations

3 REGISTRY hook di layout — tutto qui. Più iniezioni per pagina, listener di eventi del ciclo di vita e una REST API custom con namespace /api/v1/ai/*. Zero modifiche al core; la cartella plugin è deployabile drop-in.

REST API

Endpoint autenticati a token. La stessa API che usano i plugin.

Usa la REST API per integrare AcelleMail nel tuo frontend SaaS, app mobile o service Laravel. La stessa API che usano i plugin è la stessa API che usano i client esterni — niente endpoint di seconda classe.

Risorse

  • ListsGET/POST/PATCH/DELETE /api/v1/lists[/:uid]
  • Subscribers/api/v1/subscribers · tag · sub/unsub
  • Campaigns/api/v1/campaigns[/:uid] · run/pause/resume · log CSV
  • Automations/api/v1/automations[/:uid] · execute · api/call
  • Sending server/api/v1/sending_servers[/:uid]
  • Customers (admin)/api/v1/customers[/:uid] · assign/change-plan · enable/disable
  • Subscriptions (admin)/api/v1/subscriptions[/:uid]

Eventi webhook

Lifecycle (configurati in Admin → Webhooks): new_customer, new_subscription, change_plan, cancel_subscription, terminate_subscription, automation_webhook.
Tracking per destinatario (per campagna): open, click, unsubscribe.

Riferimento API completo →
# Create a list
$ curl -X POST \
    https://your-acelle.example.com/api/v1/lists \
    -H "Authorization: Bearer $ACELLE_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "Newsletter",
      "from_email": "hi@example.com",
      "from_name": "Hi Team",
      "subject": "Weekly digest"
    }'

# Add a subscriber
$ curl -X POST \
    .../api/v1/lists/:uid/subscribers \
    -H "Authorization: Bearer $ACELLE_TOKEN" \
    -d '{"EMAIL":"alice@example.com"}'

# Send a campaign
$ curl -X POST \
    .../api/v1/campaigns/:uid/send \
    -H "Authorization: Bearer $ACELLE_TOKEN"

# Receive a webhook
POST /your-webhook-endpoint
{
  "event": "campaign.sent",
  "campaign_uid": "abc123",
  "list_uid": "xyz789",
  "sent_at": "2026-05-06T12:34:56Z"
}

Etica open-source

Il tuo codice, per sempre. Niente black box, niente commissioni ricorrenti, niente squatting di namespace.

Sorgente non cifrato

Ogni riga di PHP che gira sul tuo server. Niente ionCube, niente SourceGuardian, niente offuscamento. git diff le tue personalizzazioni. grep per trovare qualsiasi cosa.

Update a vita

Ogni release di AcelleMail dal 2016 è nella tua cronologia di download su CodeCanyon. Scarica quello che vuoi quando vuoi. Nessuna pressione da abbonamento.

Il tuo namespace, per sempre

I plugin vivono sotto MyVendor\MyPlugin\ — completamente isolati dal core Acelle\*. Distribuibili via Composer al tuo team o sul marketplace.

Licenza una tantum

Paga $80 (Regular) o $199 (Extended per SaaS). Niente abbonamenti, niente per-iscritto, niente per-email. I conti non cambiano mentre cresci.

Risorse e community

Docs, plugin di esempio e una linea diretta col supporto.

Documentazione completa per sviluppatori

Undici approfondimenti source-grounded. Salta direttamente alla pagina che ti serve:

Sfoglia hub →

Guida allo sviluppo dei plugin

I cinque file lato host, il flusso di boot-and-load, i quattro stati del ciclo di vita, i due layer di injection — il modello mentale che il resto della documentazione dà per scontato.

/developers/plugin-architecture →

Riferimento REST API

Autenticazione, catalogo degli endpoint, payload dei webhook, forme degli errori — landing page nativa con esempi.

/api →

L'Hook system — quattro pattern

REGISTRY / EVENT / BEHAVIOR / FILTER — le quattro forme di estensione che i plugin usano, con call-site reali estratti dal core, semantica dei conflitti e sei anti-pattern.

/developers/hook-system →

Sending driver — pattern plugin completo

Distribuisci un MTA backend nuovo di zecca senza fare il fork del core. Il contratto register_sending_server_driver, nove marker di capacità e cinque insidie del plugin Postal.

/developers/sending-drivers →

Vetrina plugin — acelle/ai

Il plugin complesso canonico percorso da capo a fondo. Otto model, quattordici migration, diciotto locali, ogni superficie di hook, la UI del chatbox, più una ricetta di apprendimento in quattro passi.

/developers/showcase →

Supporto per sviluppatori

Bloccato su un contratto di hook o una domanda sul ciclo di vita del plugin? Scrivici — risposta tipica entro 24h.

support@acellemail.com →
Indice documentazione · CAT

Sfoglia tutti gli 11 approfondimenti →

Fondamenta, Costruzione, Qualità, Riferimento — ogni pagina in un solo posto, source-grounded contro storage/app/plugins/acelle/ai/ e le docs canoniche dei plugin.

/developers →

FAQ per sviluppatori

Le domande che gli sviluppatori fanno davvero prima di comprare.

Posso modificare il sorgente del core senza perdere gli update? +

Sì, ma il pattern più pulito è un plugin. I plugin vivono fuori dal namespace del core e sopravvivono automaticamente a ogni upgrade. Le modifiche dirette al core funzionano ma richiedono il merge manuale delle modifiche upstream a ogni release. Il sistema di plugin esiste proprio per evitare quella fatica.

I plugin sopravvivono agli upgrade di AcelleMail? +

Sì, per design. Il core dichiara i punti di hook; i plugin reagiscono. Finché il nome dell'hook e la signature restano stabili (e i breaking change li versioniamo), il tuo plugin continua a funzionare. Testiamo il plugin AI (acelle/ai) su ogni release.

Posso vendere plugin commercialmente? +

Sì. La Extended License ti permette di distribuire i tuoi plugin sotto la tua licenza. I plugin vivono nel proprio namespace; quel codice è tuo al 100%. Diversi team gestiscono marketplace privati per i propri ecosistemi interni di plugin.

Come gestisce i conflitti il sistema di plugin? +

Gli hook REGISTRY si fondono (ogni plugin contribuisce); gli hook EVENT scattano tutti (nessun conflitto possibile); le catene FILTER si accumulano; BEHAVIOR è l'unico pattern "esclusivo" — se due plugin provano a rivendicare lo stesso behavior, viene lanciata un'eccezione immediatamente. Nessuna sorpresa di override silenziosi.

I plugin possono parlare tra loro? +

Sì, tramite lo stesso Hook system. Il plugin A può lanciare eventi su cui il plugin B può mettersi in ascolto. Oppure esporre una classe pubblica — MyVendor\PluginA\Service è una normale classe PHP, importabile come qualsiasi altra. Il plugin acelle/ai espone hook per altri plugin per registrare tool AI custom.

Qual è la differenza fra Regular ed Extended per uno sviluppatore? +

Regular ($80) copre il tuo uso su un singolo dominio. Extended ($199) aggiunge il diritto di addebitare gli utenti finali (rivendere come SaaS), distribuire cloni white-label e vendere i tuoi plugin. Entrambe distribuiscono lo stesso sorgente.

Le migration dei plugin toccano il DB principale? +

Scrivono sullo stesso database, ma in tabelle con prefisso del nome vendor (es. myvendor_loyalty_accounts). Le migration girano all'attivazione del plugin, fanno rollback all'eliminazione con $keepData = false. Zero rischio per le tabelle del core.

Posso scrivere plugin in qualcosa che non sia PHP? +

Il runtime dei plugin è PHP/Laravel. Ma il tuo plugin può fare shell out verso qualsiasi cosa — service Node, ML in Python, binari Go, API HTTP esterne. Diversi team distribuiscono plugin che fanno da wrapper a tool esterni. Il plugin è la shell di integrazione; il lavoro pesante può vivere ovunque.

Come interagiscono i plugin col sottosistema AI? +

acelle/ai espone hook che altri plugin possono usare per registrare tool AI custom, scambiare motori o agganciarsi al layer di observability. Leggi il sorgente del plugin AI per il contratto. Il tuo plugin può anche lanciare eventi che l'agent AI raccoglie come contesto.

Esiste un marketplace per i plugin? +

Non ancora. Oggi i plugin si distribuiscono via vendita diretta, GitHub o il tuo registry privato. Un marketplace community è in roadmap quando esisteranno abbastanza plugin di terze parti da renderlo sensato.

Distribuisci il tuo primo plugin questo pomeriggio.

Sorgente PHP completo. Update a vita. L'Hook system. Esempi reali in produzione da cui copiare. $199 una tantum per la Extended License (redistribuzione commerciale di plugin + uso SaaS).

Acquista Extended License — $199 Prova la Live Demo