Skip to content

Email Studio

This page is generated from public package documentation in capell-4/packages and the package manifest checked into the source repository.

FieldValue
Composer packagecapell-app/email-studio
Package slugemail-studio
Product groupCapell Communications
Tierpremium
Bundlecommunications
Runtime contextsadmin, frontend, console
Capell version^4.0
Source repositorycapell-app/packages
Source pathpackages/email-studio
Docs sourcepackages/email-studio/docs
Manifestcapell.json

Template-driven transactional email, delivery auditing, provider events, replies, and suppressions for Capell CMS.

  • Package: capell-app/email-studio
  • Namespace: Capell\EmailStudio\
  • Surfaces: HTTP, queue, database
  • Service providers: packages/email-studio/src/Providers/AdminServiceProvider.php, packages/email-studio/src/Providers/EmailStudioServiceProvider.php, packages/email-studio/src/Providers/FrontendServiceProvider.php
  • Capell dependencies: capell-app/admin, capell-app/core, capell-app/frontend
  • Gives Capell a transactional email center for reusable templates, provider delivery, suppressions, replies, and event audit.
  • Helps owners keep email behavior visible in admin instead of burying delivery state inside provider dashboards.
  • Gives developers provider adapters and send Actions so forms, automations, and workflow packages can send consistently.
  • Template-driven transactional email, delivery auditing, provider events, replies, and suppressions for Capell CMS.

For developers, Email Studio removes the need for each package to build its own mailer conventions. Packages pass a SendEmailData object into one Action and get rendering, suppression checks, queue dispatch, provider selection, and audit records through the same path.

For teams, it creates one place to answer practical support questions:

  • Which template was used?
  • Which profile sent it?
  • Who received it?
  • Was the recipient suppressed?
  • Did the provider accept or reject the message?
  • Which payload and context were used at send time?

That is the part clients pay for. Sending an email is easy; proving what happened later is where the product value sits.

  • EmailStudioServiceProvider registers config, translations, routes, migrations, models, and provider adapters.
  • AdminServiceProvider and FrontendServiceProvider reserve the admin and public route surfaces for later slices.
  • EmailTemplateRegistry stores package-owned template registrations.
  • EmailVariableRenderer performs controlled {{ variable }} substitution using declared template variables.
  • EmailProfileResolver resolves a requested profile or the best default profile for the site scope.
  • EmailProviderRegistry isolates provider adapters from the send pipeline.
  • SendEmailAction creates the message and recipient records, renders the selected variant, applies suppression state, and queues delivery.
  • DeliverEmailMessageAction rechecks suppressions, calls the provider adapter, and records recipient/message outcomes.
AreaPathPurpose
Actionspackages/email-studio/src/ActionsDomain operations. Test these directly where possible.
Datapackages/email-studio/src/DataStructured payloads, form state, view models, and integration data.
Enumspackages/email-studio/src/EnumsPersisted states and Filament option values.
Modelspackages/email-studio/src/ModelsEloquent records owned by the package.
Jobspackages/email-studio/src/JobsQueued work and async side effects.
Providerspackages/email-studio/src/ProvidersRegistration, extension hooks, routes, migrations, and resources.
Resourcespackages/email-studio/resourcesViews, translations, assets, and package resources.
Routespackages/email-studio/routesRoute files loaded by the service provider.
Configpackages/email-studio/configPackage configuration and publishable config.
Databasepackages/email-studio/databaseMigrations, seeders, and settings migrations.
Testspackages/email-studio/testsPackage-level Pest coverage.
  • Routes: packages/email-studio/routes/web.php.
  • Jobs: SendEmailJob.
  • Models: EmailEvent, EmailMessage, EmailProfile, EmailRecipient, EmailReply, EmailSuppression, EmailTemplate, EmailTemplateRegistration, EmailTemplateVariant, EmailTrackingToken.
  • Migrations: 2026_05_10_190847_01_create_email_profiles_table.php, 2026_05_10_190847_02_create_email_templates_table.php, 2026_05_10_190847_03_create_email_template_variants_table.php, 2026_05_10_190847_04_create_email_messages_table.php, 2026_05_10_190847_05_create_email_recipients_table.php, 2026_05_10_190847_06_create_email_events_table.php, 2026_05_10_190847_07_create_email_replies_table.php, 2026_05_10_190847_08_create_email_suppressions_table.php, 2026_05_10_190847_09_create_email_template_registrations_table.php, 2026_05_10_190847_10_create_email_tracking_tokens_table.php.
  • Config: packages/email-studio/config/capell-email-studio.php.
  • Data objects live in src/Data/; use them for payloads, form state, and view models.
  • Contracts: EmailProviderAdapter.
  • Register Capell extension points, routes, migrations, settings, render hooks, and resources from service providers.
  • Install with composer require capell-app/email-studio in the host Capell application.
  • Run migrations through the host application package install flow.
  • In this repository, verify package changes with vendor/bin/pest; do not use php artisan.
  • Only approved templates can be used for production sends.
  • Only active variants are resolved.
  • A send with no recipients fails before creating a message record.
  • Suppressions are checked twice because an address can be suppressed after queueing and before delivery.
  • Provider-level failures and adapter exceptions are recorded on the Email Studio message and recipients.
  • If no locale is provided to SendEmailData, the send uses Laravel’s current locale and falls back to a neutral variant.

Run package tests from the repository root:

Terminal window
vendor/bin/pest packages/email-studio/tests --configuration=phpunit.xml
  • Put behaviour changes in src/Actions/; UI classes, commands, and controllers should call actions instead of owning domain logic.
  • Use package Data classes at boundaries instead of passing anonymous arrays between layers.
  • Use backed enums for persisted values and enum labels for Filament options.