Guide
How to send email with Laravel
Send email from Laravel with the built-in HTTP client.
In short
Create a Sendpository account, verify your domain, put your API key inSENDPOSITORY_API_KEY, and send with the code below - one HTTPS request per email, from server-side code only.1. Verify your sending domain
Add your domain in the dashboard and publish the three DNS records it shows - SPF and a bounce record on an sp. subdomain, and a DKIM key on your apex. Your existing records are never edited. Verification usually lands in a few minutes, and you can set up the code below while you wait.
2. Create a key
Create an API key with the sending permission. It is shown once, so put it straight into your secrets. Add SENDPOSITORY_API_KEY to .env and expose it through config/services.php.
3. Send an email
// config/services.php
'sendpository' => ['key' => env('SENDPOSITORY_API_KEY')],
// app/Services/Mailer.php
use Illuminate\Support\Facades\Http;
public function send(string $to, string $subject, string $html): string
{
$response = Http::withToken(config('services.sendpository.key'))
->timeout(10)
->post('https://api.sendpository.com/v1/emails', [
'from' => 'Your App <hello@mail.yourdomain.com>',
'to' => [$to],
'subject' => $subject,
'html' => $html,
])
->throw();
return $response->json('id');
}A success returns { "id": "..." } - the message’s id for looking it up later. A failure returns { "error": { "type", "message" } } with a 4xx or 5xx status.
Queue it
Dispatch a job rather than sending in the controller. Laravel already gives you the queue, the retry policy and the failed-jobs table - using it means a transient 5xx retries itself instead of surfacing as a 500 to the user.
Use `dispatch()->afterCommit()` so the job only runs once the database transaction has committed. Otherwise a queue worker can pick the job up before the row it refers to exists.
Testing it
- Put the key in `.env` and read it through `config()`, never `env()` outside config files - `php artisan config:cache` in production makes direct `env()` calls return null.
- `Http::fake()` in tests lets you assert the request was made and its shape, without a network call.
Things to know
- Render Blade views with view('emails.welcome', $data)->render() and pass the HTML.
- Dispatch from a queued job so the HTTP call never blocks a web request.
Questions
Why is my queued email sent before the record exists?
The job was enqueued inside a transaction and picked up before the commit. Use `dispatch()->afterCommit()`, or set `after_commit` on the queue connection, so the worker only sees the job once the data it refers to is really there.
How do I send email with Laravel?
Verify your sending domain, create an API key, put it in an environment variable, and POST the message as JSON to https://api.sendpository.com/v1/emails from server-side Laravel code. The example on this page runs as written once the domain is verified.
Can I send email with Laravel without SMTP?
Yes. This is plain HTTPS, so Laravel needs no mail library and no SMTP port - which matters on hosts that block outbound 25 and 587. Failures come back as a status code on the call instead of as a bounce message hours later.
More guides
Send your first email in minutes
6,000 emails a month (up to 200 a day), free forever. No card needed.