Pour les développeurs

Construisez des plugins. Pas des contournements.

AcelleMail est une plateforme d'email marketing Laravel 11+ qui est livrée avec son source PHP complet, non chiffré — et un système de Hooks typé qui permet à vos plugins d'ajouter des drivers d'envoi, des passerelles de paiement, de l'IA, de l'UI sur mesure, voire des REST APIs. Sans forker le core.

De vrais plugins qui sortent aujourd'hui

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…

Pourquoi les développeurs choisissent AcelleMail

Bâtie sur le framework que vous connaissez déjà.
Étendue via des patterns que vous utilisez déjà.

PHP / Laravel open source

Le source PHP complet et non chiffré est livré avec chaque licence. Modifiez n'importe quelle classe, surchargez n'importe quel service, forkez dans votre propre namespace — votre code, vos règles. Bâtie sur Laravel 11+, le framework que vous connaissez déjà fait le gros du travail.

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

Architecture en plugins

Déposez un dossier au format Composer sous storage/app/plugins/<vendor>/<name>/ et l'application l'autoload. Le ServiceProvider injecte les routes, vues, migrations, hooks — activez, désactivez, supprimez proprement.

$ php artisan plugin:init myvendor/loyalty

REST API authentifiée par token

Endpoints CRUD pour campagnes, listes, abonnés, modèles, automatisations. Événements webhook pour chaque action métier. Prête à brancher pour des frontends SaaS, des apps mobiles ou d'autres services Laravel. La même API que les plugins utilisent est celle que les clients externes utilisent — aucun endpoint de seconde zone.

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

Auto-hébergée sur votre infra

Votre serveur, votre DB, vos données d'abonnés. Aucun lock-in fournisseur. Payez une fois la licence ; ne payez ensuite que le coût SMTP sous-jacent (par exemple Amazon SES à 0,10 $/1 000). Déployez partout où PHP tourne — bare metal, Kubernetes, Forge, Laravel Vapor. Scalez comme votre stack scale.

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

Ce que vous pouvez construire avec des plugins

14 surfaces d'extension.
Chacune avec un vrai exemple de production aujourd'hui.

Un plugin est un package Laravel autonome qui vit sur le disque, possède son propre namespace, ses propres tables de base de données, routes, vues, contrôleurs, modèles — et s'intègre au core via un système de Hooks typé, plutôt que via des bidouilles à coups de include.

Drivers et intégrations · 4

Serveurs d'envoi / drivers REGISTRY
register_sending_server_driver
rencontru/postal — driver MTA Postal sous forme de plugin drop-in
Vérification d'e-mails / délivrabilité REGISTRY
REGISTRY + FILTER
athena/evs — sous-système de vérification avec UI admin
Passerelles de paiement REGISTRY
REGISTRY
Stripe / PayPal / Braintree / Paystack / Razorpay / Coinbase intégrés montrent le pattern
IA / chatbot / assistants REGISTRY
REGISTRY + EVENT
acelle/ai — chatbox + sparkle + observabilité

UI et pages · 5

Injection d'UI sur mesure REGISTRY
layout.head.assets / layout.body.before_close / admin.sidebar.groups
Chatbox + popover sparkle de acelle/ai
Emplacements de contenu au niveau page REGISTRY
page.{ctrl}.{action}.{slot}
page.maillist.show.body, page.campaign.index.sidebar
Pages d'administration ROUTE
Laravel routes
/rui/admin/ai-usage, /rui/admin/ai-audit, /rui/admin/ai-conversations
Pages côté client ROUTE
Laravel routes
/plugins/acelle/ai/dashboard
REST APIs ROUTE
Routes + api.access_token
/api/v1/ai/* dans acelle/ai

Données et cycle de vie · 2

Modèles Eloquent personnalisés + tables DB BEHAVIOR
Plugin-isolated migrations
acelle/ai livre 8 modèles / 12 migrations, noms de tables préfixés par vendor
Traductions (18 locales) REGISTRY
add_translation_file
acelle/ai livre 162 fichiers de langue (18 × 9)

Comportement et flux · 3

Listeners de webhook / événements métier EVENT
Hook::on(…)
customer_added, plan_changed, subscription_terminated
Surcharges de comportement BEHAVIOR
Hook::set / setIfEmpty / perform
dispatch_list_import_job — remplace entièrement la logique d'import
Chaînes de filtres FILTER
Hook::modify / filter
sidebar-menu-items, mutation du contenu pré-envoi, URLs de redirection

Un seul plugin peut combiner n'importe lesquelles de ces surfaces — acelle/ai en utilise 7 sur 14 dans un seul package.

Le système de Hooks

Quatre patterns d'extension typés. Aucune surcharge surprise. Aucun conflit silencieux.

Le core n'importe jamais du code de plugin — il déclare uniquement des points d'extension. Les plugins écoutent et réagissent. Quatre patterns, chacun avec un rôle clair. Les conflits sont levés immédiatement.

1

REGISTRY add() + collect()

Le plugin contribue des éléments à une liste. Le core demande « qui a un driver d'envoi ? » et votre plugin répond « moi, j'en ai un ».


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()

Le plugin réagit quand quelque chose se passe. Les valeurs de retour sont ignorées.


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


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

BEHAVIOR set() + perform()

Le plugin remplace complètement un morceau de logique du core. Un seul plugin peut revendiquer un comportement donné — les conflits sont levés immédiatement.


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()

Le plugin transforme une valeur à travers une chaîne de callbacks. Chaque callback reçoit la valeur courante, retourne la valeur modifiée.


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 en 5 minutes

Un plugin fonctionnel à partir de zéro en huit commandes.

Le scaffold crée tout — métadonnées Composer, ServiceProvider, modèle d'exemple, migration d'exemple, route d'exemple, vue d'exemple. À partir de là, c'est à vous de le faire grandir.

  1. 1

    Scaffolder le plugin

    Crée la structure de dossiers standard + une ligne DB inactive.

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

    Éditez composer.json

    Indiquez à Composer votre namespace et le 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

    Écrivez une migration

    Table isolée au plugin, nom préfixé par vendor. Tourne à l'activation, rollback à la suppression.

    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

    Définissez un modèle

    Modèle Eloquent standard dans votre propre 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

    Ajoutez un contrôleur et une vue

    Contrôleur Laravel classique — le namespace de vue est le nom de votre 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

    Déclarez les routes

    Même Route::group que vous utilisez déjà. Chargée par 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

    Branchez le tout dans ServiceProvider::boot()

    Chargez vues + routes ; raccrochez-vous au hook activate_plugin_… pour migrer à l'activation.

    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

    Activez depuis l'admin

    Rendez-vous sur /rui/admin/plugins. Les migrations tournent automatiquement. Le plugin vit sous son préfixe.

    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

Vous avez maintenant un plugin fonctionnel. Ajoutez autant de modèles, contrôleurs et hooks que votre fonctionnalité exige. Les tests vivent dans tests/ ; lancez-les avec php artisan test --testsuite='Plugin: myvendor/loyalty'. Sourcez le contrat canonique dans la base de connaissances.

Cycle de vie d'un plugin

Quatre états. Des transitions prévisibles. Aucun mystère du genre « est-ce que ça a tourné ? ».

Chaque plugin vit dans exactement un de quatre états. L'état dans lequel vous êtes dicte quels hooks se déclenchent, quelles migrations ont tourné et ce qui se passe à la prochaine transition. Sourcé contre docs/plugin/SOURCE_OF_TRUTH.md.

STATE 01 register (inactif) Dossier de plugin découvert. index.json + ligne DB existent. Les hooks NE se déclenchent PAS. STATE 02 active Tous les hooks sont actifs. Routes montées. Migrations ont tourné. activate_plugin_… s'est déclenché une fois. STATE 03 inactive (en pause) Dossier toujours sur disque. Hooks en pause. Routes démontées. Tables DB intactes. STATE 04 deleted (parti) Dossier supprimé. Migrations rollbackées si $keepData = false. Ligne DB supprimée. activate les migrations tournent deactivate données conservées remove $keepData ? re-activate le hook activate NE se re-déclenche PAS
Register · inactif

Découvert, mais pas en cours d'exécution

Le dossier du plugin existe, index.json est indexé, la ligne DB dit inactive. La méthode register() du ServiceProvider a tourné, mais les hooks de boot() restent gattés tant que vous n'avez pas cliqué Activer.

Actif

Vivant, hooks en cours

La première activation déclenche activate_plugin_<name> une fois — c'est là que les migrations tournent. Ensuite, tous les hooks REGISTRY / EVENT / FILTER / BEHAVIOR sont actifs jusqu'à la désactivation.

Inactif · en pause

En pause, données intactes

Les routes se démontent, les hooks se gattent, mais le dossier + les tables DB restent. La réactivation ne re-déclenche pas les migrations ni le hook activate — sans risque de toggle en production.

Supprimé

Retiré proprement

Dossier supprimé, ligne DB partie. Si $keepData = false, les migrations du plugin sont rollbackées — les tables préfixées par vendor sont droppées. Les tables du core ne sont jamais touchées.

Vitrine de plugin réel

acelle/ai — tout un sous-système IA dans un seul dossier de plugin.

Le plugin acelle/ai livre une couche d'assistant IA complète : chatbox agent sur chaque page, réécriture sparkle ✨ de texte sur les champs rich-text, personas coach ancrés sur la KB (Délivrabilité, Segments, Campagnes, Formulaires), et une surface d'observabilité admin sur 5 routes. Il se monte via 3 hooks de layout. Zéro changement au core.

Plugin acelle/ai en action — bulle flottante AcelleMail AI chatbox avec le popover sparkle ✨ pour la réécriture en un clic, plus le groupe de sidebar admin du plugin rendu dans l'UI AcelleMail

Ce qu'il livre

  • Chatbox flottante — mode support pur + mode agent opt-in qui appelle des outils
  • Popover sparkle — réécriture / extension / simplification en un clic sur chaque champ rich-text
  • Personas coach — assistants LLM domaine-spécifiques, ciblés par écran
  • Observabilité admin — usage, audit, conversations, feedback, amélioration continue
  • Flexibilité de moteur — BYO OpenAI, Anthropic ou Ollama local
  • Page de plugin landing à /plugins/acelle/ai/dashboard

En chiffres

8
Modèles Eloquent
12
Migrations
60+
Templates Blade
100+
Tests Pest
18 × 9
Locales × fichiers de langue
~35
Fichiers CSS + JS

Comment il se monte — 3 hooks

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 hooks REGISTRY de layout — c'est tout. Plus des injections par page, des listeners d'événements de cycle de vie, et une REST API custom namespacée à /api/v1/ai/*. Zéro changement au core ; le dossier du plugin est déployable en drop-in.

REST API

Endpoints authentifiés par token. La même API que les plugins utilisent.

Utilisez la REST API pour intégrer AcelleMail dans votre propre frontend SaaS, app mobile ou service Laravel. La même API que les plugins utilisent est celle que les clients externes utilisent — aucun endpoint de seconde zone.

Ressources

  • ListesGET/POST/PATCH/DELETE /api/v1/lists[/:uid]
  • Abonnés/api/v1/subscribers · tags · sub/unsub
  • Campagnes/api/v1/campaigns[/:uid] · run/pause/resume · log CSVs
  • Automatisations/api/v1/automations[/:uid] · execute · api/call
  • Serveurs d'envoi/api/v1/sending_servers[/:uid]
  • Customers (admin)/api/v1/customers[/:uid] · assign/change-plan · enable/disable
  • Abonnements (admin)/api/v1/subscriptions[/:uid]

Événements webhook

Cycle de vie (configuré dans Admin → Webhooks) : new_customer, new_subscription, change_plan, cancel_subscription, terminate_subscription, automation_webhook.
Tracking par destinataire (par campagne) : open, click, unsubscribe.

Référence complète de l'API →
# 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"
}

Éthique open source

Votre code, pour toujours. Pas de boîtes noires, pas de frais récurrents, pas de squat de namespace.

Source non chiffré

Chaque ligne de PHP qui tourne sur votre serveur. Pas d'ionCube, pas de SourceGuardian, pas d'obfuscation. git diff sur vos personnalisations. grep pour trouver n'importe quoi.

Mises à jour à vie

Chaque release de AcelleMail depuis 2016 est dans votre historique de téléchargement CodeCanyon. Récupérez ce que vous voulez quand vous le voulez. Aucune pression d'abonnement.

Votre namespace, pour toujours

Les plugins vivent sous MyVendor\MyPlugin\ — complètement isolés du core Acelle\*. Distribuables via Composer à votre équipe ou marketplace.

Licence en paiement unique

Payez $80 (Regular) ou $199 (Extended pour SaaS). Aucun abonnement, aucun coût par abonné, aucun coût par e-mail. La formule ne change pas quand vous grandissez.

Ressources et communauté

Doc, plugins d'exemple et ligne directe avec le support.

Documentation développeur complète

Onze approfondissements sourcés. Filez directement sur la page dont vous avez besoin :

Parcourir le hub →

Guide de développement de plugins

Cinq fichiers côté host, le flux boot-and-load, les quatre états du cycle de vie, les deux couches d'injection — le modèle mental que le reste de la doc présuppose.

/developers/plugin-architecture →

Référence REST API

Authentification, catalogue d'endpoints, charges utiles webhook, formes d'erreur — page de landing native avec exemples.

/api →

Le système de Hooks — quatre patterns

REGISTRY / EVENT / BEHAVIOR / FILTER — les quatre formes d'extension que les plugins utilisent, avec de vrais points d'appel grepés depuis le core, la sémantique des conflits et six anti-patterns.

/developers/hook-system →

Drivers d'envoi — pattern de plugin complet

Livrez un backend MTA flambant neuf sans forker le core. Le contrat register_sending_server_driver, neuf marqueurs de capacité et cinq pièges du plugin Postal.

/developers/sending-drivers →

Vitrine de plugin — acelle/ai

Le plugin complexe canonique parcouru de bout en bout. Huit modèles, quatorze migrations, dix-huit locales, chaque surface de hook, l'UI de la chatbox, plus une recette d'apprentissage en quatre étapes.

/developers/showcase →

Support développeur

Bloqué sur un contrat de hook ou une question de cycle de vie de plugin ? Écrivez-nous — réponse typique sous 24 h.

support@acellemail.com →
Index de la documentation · CAT

Parcourir les 11 approfondissements →

Fondations, Construction, Qualité, Référence — chaque page au même endroit, sourcée contre storage/app/plugins/acelle/ai/ et la doc canonique des plugins.

/developers →

FAQ développeurs

Les questions que les développeurs posent réellement avant d'acheter.

Puis-je modifier le code source du core sans perdre les mises à jour ? +

Oui, mais le pattern le plus propre est un plugin. Les plugins vivent en dehors du namespace du core et survivent à chaque upgrade automatiquement. Les édits directs au core fonctionnent, mais demandent de merger manuellement les changements upstream à chaque release. Le système de plugins existe précisément pour vous éviter cette corvée.

Les plugins survivent-ils aux upgrades de AcelleMail ? +

Oui, par conception. Le core déclare les points de hook ; les plugins réagissent. Tant que le nom et la signature du hook restent stables (et nous version-stampons les changements cassants), votre plugin continue de fonctionner. Nous testons le plugin AI (acelle/ai) à chaque release.

Puis-je vendre des plugins commercialement ? +

Oui. La Licence Extended vous permet de distribuer vos propres plugins sous votre propre licence. Les plugins vivent dans leur propre namespace ; vous possédez ce code à 100 %. Plusieurs équipes opèrent des marketplaces privés pour leurs écosystèmes de plugins internes.

Comment le système de plugins gère-t-il les conflits ? +

Les hooks REGISTRY mergent (chaque plugin contribue) ; les hooks EVENT se déclenchent tous (aucun conflit possible) ; les chaînes FILTER s'accumulent ; BEHAVIOR est le seul pattern « exclusif » — si deux plugins essaient de revendiquer le même behavior, une exception est levée immédiatement. Aucune surprise de surcharge silencieuse.

Les plugins peuvent-ils communiquer entre eux ? +

Oui, via le même système de Hooks. Le plugin A peut déclencher des événements que le plugin B écoute. Ou exposer une classe publique — MyVendor\PluginA\Service est une classe PHP classique, importable comme n'importe quelle autre. Le plugin acelle/ai expose des hooks que d'autres plugins peuvent utiliser pour enregistrer des outils IA personnalisés.

Quelle est la différence entre Regular et Extended pour un développeur ? +

Regular ($80) couvre votre propre utilisation sur un seul domaine. Extended ($199) ajoute le droit de facturer les utilisateurs finaux (revente en SaaS), de distribuer des clones white-label et de vendre vos propres plugins. Les deux livrent le même code source.

Les migrations de plugins touchent-elles la DB principale ? +

Elles écrivent dans la même base de données, mais dans des tables préfixées par votre nom de vendor (par ex. myvendor_loyalty_accounts). Les migrations tournent à l'activation du plugin, sont rollbackées à la suppression du plugin avec $keepData = false. Zéro risque pour les tables du core.

Puis-je écrire des plugins dans autre chose que PHP ? +

Le runtime des plugins est PHP/Laravel. Mais votre plugin peut shellsout vers n'importe quoi — services Node, ML Python, binaires Go, APIs HTTP externes. Plusieurs équipes livrent des plugins qui wrapent des outils externes. Le plugin est la coquille d'intégration ; le gros du travail peut vivre n'importe où.

Comment les plugins interagissent-ils avec le sous-système IA ? +

acelle/ai expose des hooks que d'autres plugins peuvent utiliser pour enregistrer des outils IA personnalisés, changer de moteur ou se brancher sur la couche d'observabilité. Lisez le source du plugin AI pour le contrat. Votre plugin peut aussi déclencher des événements que l'agent IA récupère comme contexte.

Y a-t-il une marketplace de plugins ? +

Pas encore. Aujourd'hui, les plugins se distribuent via vente directe, GitHub ou votre registre privé. Une marketplace communautaire est sur la roadmap dès qu'assez de plugins tiers existeront pour la rendre intéressante.

Livrez votre premier plugin cet après-midi.

Code source PHP complet. Mises à jour à vie. Le système de Hooks. De vrais exemples de production à recopier. $199 en paiement unique pour la Licence Extended (redistribution commerciale de plugins + usage SaaS).

Acheter la Licence Extended — $199 Essayer la démo en direct