Guides
Send email with Laravel
One injectable service on the built-in HTTP client, keyed through config, queued when it matters.
Facts verified 2026-07-17 — corrections: hello@emailfast.dev
In Laravel, wrap the API in one small injectable service — the same shape you'd give a custom notification channel — and read the key through config(), not env(). Laravel's built-in HTTP client does the POST, so there is nothing new to install.
<?php
// app/Services/EmailFast.php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class EmailFast
{
public function send(
string $to,
string $subject,
string $html,
array $data = [],
?string $idempotencyKey = null,
): array {
return Http::withToken(config('services.emailfast.key'))
->timeout(10)
->post('https://api.emailfast.dev/v1/emails', [
'to' => $to,
'subject' => $subject,
'html' => $html,
'data' => $data,
'idempotency_key' => $idempotencyKey,
])
->throw()
->json();
}
}// config/services.php
'emailfast' => ['key' => env('EMAILFAST_API_KEY')], // ef_sandbox_... while testing// anywhere — a controller, a queued job, a listener
app(\App\Services\EmailFast::class)->send(
to: $user->email,
subject: 'Confirm your account',
html: '<p>Hi {{name}}, confirm your address here.</p>',
data: ['name' => $user->name],
idempotencyKey: "confirm-{$user->id}", // a queue retry replays, never re-sends
);a 202 from the API means the send is committed to a durable, partitioned outbox before we answer — a crash can't lose it, and a retry with the same idempotency key can't double-send.
Gotchas
env()returnsnullonce you runphp artisan config:cache— onlyconfig/services.phpmay call it. Everywhere else,config('services.emailfast.key').- Send from a queued job or a
ShouldQueuelistener so email never adds latency to a web request; the idempotency key is what makes queue retries safe. - Using Laravel notifications? Lift this service into a custom channel (
via()returning your channel class) and keep it as the single door to the API. ->throw()puts the API's error body in the exception message — log it; it names the exact rejection reason (invalid address, suppressed recipient, quota).
Next
- PHP SDK quickstart — the typed client
- The email API — batch, scheduling, message timelines
- Plain PHP recipe
- All docs