Skip to content

Email Studio API

Email Studio exposes Actions and Data objects as its package API. Controllers, Filament resources, listeners, and other packages should call these Actions instead of writing directly to the email tables.

Use RegisterEmailTemplateAction when a package owns a template definition.

use Capell\EmailStudio\Actions\RegisterEmailTemplateAction;
RegisterEmailTemplateAction::run(
key: 'forms.confirmation',
name: 'Form confirmation',
variables: ['name', 'submission_reference'],
description: 'Sent after a successful form submission.',
packageName: 'capell-app/form-builder',
siteId: null,
siteScopeKey: 'global',
);

Registrations are upserted by package, key, and site scope. They describe the expected template contract; the actual approved sendable content lives in EmailTemplate and EmailTemplateVariant.

SendEmailAction is the canonical entrypoint.

use Capell\EmailStudio\Actions\SendEmailAction;
use Capell\EmailStudio\Data\EmailAddressData;
use Capell\EmailStudio\Data\EmailHeaderData;
use Capell\EmailStudio\Data\SendEmailData;
use Spatie\LaravelData\DataCollection;
SendEmailAction::run(new SendEmailData(
templateKey: 'forms.confirmation',
to: new DataCollection(EmailAddressData::class, [
new EmailAddressData('[email protected]', 'Customer Name'),
]),
cc: new DataCollection(EmailAddressData::class, []),
bcc: new DataCollection(EmailAddressData::class, []),
siteId: 12,
siteScopeKey: 'site:12',
emailProfileId: null,
variables: [
'name' => 'Customer Name',
'submission_reference' => 'FS-1001',
],
headers: new DataCollection(EmailHeaderData::class, []),
triggeredByType: 'form_submission',
triggeredById: 1001,
queue: true,
locale: 'en',
));

The Action:

  • resolves a profile from the requested site scope;
  • resolves an approved template;
  • resolves an active variant for the requested or current locale;
  • renders declared variables;
  • creates the message and recipient rows;
  • applies suppressions;
  • dispatches SendEmailJob when queueing is enabled.

Pass queue: false only for tests or controlled workflows that need immediate delivery.

Use RenderEmailTemplateAction when the admin UI needs a preview.

use Capell\EmailStudio\Actions\RenderEmailTemplateAction;
use Capell\EmailStudio\Data\EmailContextData;
$rendered = RenderEmailTemplateAction::run(
variant: $variant,
context: new EmailContextData(
variables: ['name' => 'Customer Name'],
preview: true,
),
);

Preview mode leaves missing markers visible. Production mode throws EmailTemplateRenderingException when a variable is missing or undeclared.

Use ResolveEmailTemplateVariantAction to select the sendable content for a template.

$variant = ResolveEmailTemplateVariantAction::run(
template: $template,
siteScopeKey: 'site:12',
locale: 'en',
);

Resolution order:

  1. requested site scope before global;
  2. requested locale before neutral locale;
  3. latest version among matching active variants.

When no locale is supplied, the resolver only returns neutral variants. SendEmailAction supplies Laravel’s current locale by default.

Use SuppressEmailAddressAction to add or reactivate a suppression.

use Capell\EmailStudio\Actions\SuppressEmailAddressAction;
use Capell\EmailStudio\Enums\SuppressionReason;
SuppressEmailAddressAction::run(
reason: SuppressionReason::Complaint,
siteId: null,
siteScopeKey: 'global',
source: 'provider',
);

Use CheckEmailSuppressionAction when another integration needs to check before offering an email workflow.

$suppressed = CheckEmailSuppressionAction::run('[email protected]', 'site:12');

Global suppressions apply to every site. Site-scoped suppressions apply only to that site scope.

Providers implement EmailProviderAdapter.

use Capell\EmailStudio\Contracts\EmailProviderAdapter;
use Capell\EmailStudio\Enums\EmailProviderType;
use Capell\EmailStudio\Support\EmailProviderRegistry;
resolve(EmailProviderRegistry::class)->register(
EmailProviderType::Fake,
new CustomProviderAdapter(),
);

Adapters return ProviderSendResultData. A provider-level failure should return successful: false and a failure reason. If the adapter throws, DeliverEmailMessageAction records the message and queued recipients as failed.

EmailStudioSendingException is thrown when:

  • no recipients are provided;
  • no profile is available;
  • no approved template is available;
  • no active variant is available;
  • a provider adapter is not registered.

Provider transport failures are recorded on the message and recipients instead of bubbling through as unrecorded queue failures.