> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sendbaze.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Send emails with PHP

> Learn how to send your first email from PHP or Laravel with the Sendbaze REST API.

## Prerequisites

* A Sendbaze [API key](https://docs.sendbaze.com/get-started/create-api-key.md)
* A [verified domain](https://docs.sendbaze.com/get-started/add-domain.md). A test key works without one, and so does the [shared test address](https://docs.sendbaze.com/get-started/test-without-a-domain.md) for emails to yourself.
* PHP 8.1 or later with the `curl` extension

## Guide

**1. Set your API key**

```bash .env theme={"dark"}
SENDBAZE_API_KEY=sk_live_xxxxxxxx
```

**2. Send an email**

```php Plain PHP theme={"dark"}
<?php
$payload = [
    'from' => 'Yourshop <orders@yourshop.co.za>',
    'to' => 'thandi@example.com',
    'subject' => 'Your order #1042 has shipped',
    'html' => '<p>Tracking: <b>CG123456789ZA</b></p>',
];

$ch = curl_init('https://api.sendbaze.com/v1/emails');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('SENDBAZE_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_TIMEOUT => 30,
]);
$response = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new RuntimeException($response['error']['code'] . ': ' . $response['error']['message']);
}
echo $response['id']; // em_01j9...
```

```php Laravel (Http facade) theme={"dark"}
<?php
use Illuminate\Support\Facades\Http;

$response = Http::withToken(config('services.sendbaze.key'))
    ->timeout(30)
    ->post('https://api.sendbaze.com/v1/emails', [
        'from' => 'Yourshop <orders@yourshop.co.za>',
        'to' => 'thandi@example.com',
        'subject' => 'Your order #1042 has shipped',
        'html' => '<p>Tracking: <b>CG123456789ZA</b></p>',
    ]);

if ($response->failed()) {
    report(new RuntimeException($response->json('error.code') . ': ' . $response->json('error.message')));
}

$id = $response->json('id'); // em_01j9...
```

```php Guzzle theme={"dark"}
<?php
use GuzzleHttp\Client;

$client = new Client(['base_uri' => 'https://api.sendbaze.com', 'timeout' => 30]);
$response = $client->post('/v1/emails', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('SENDBAZE_API_KEY')],
    'json' => [
        'from' => 'Yourshop <orders@yourshop.co.za>',
        'to' => 'thandi@example.com',
        'subject' => 'Your order #1042 has shipped',
        'html' => '<p>Tracking: <b>CG123456789ZA</b></p>',
    ],
]);
$id = json_decode($response->getBody(), true)['id'];
```

**3. Try it**

Run the script and open the dashboard **Logs**.

## Examples

### Laravel: config and a queued job

```php config/services.php theme={"dark"}
'sendbaze' => [
    'key' => env('SENDBAZE_API_KEY'),
],
```

```php app/Jobs/SendReceipt.php theme={"dark"}
<?php
namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Http;

class SendReceipt implements ShouldQueue
{
    use Queueable;

    public function __construct(public int $orderId, public string $to, public string $name) {}

    public function handle(): void
    {
        Http::withToken(config('services.sendbaze.key'))
            ->withHeaders(['Idempotency-Key' => "receipt-{$this->orderId}"])
            ->post('https://api.sendbaze.com/v1/emails', [
                'from' => 'orders@yourshop.co.za',
                'to' => $this->to,
                'templateId' => 'tpl_receipt',
                'variables' => ['name' => $this->name, 'order_id' => $this->orderId],
                'tags' => ['receipt'],
            ])
            ->throw();
    }
}
```

### Attach a file

```php theme={"dark"}
$payload['attachments'] = [[
    'filename' => 'invoice-1042.pdf',
    'contentType' => 'application/pdf',
    'content' => base64_encode(file_get_contents('invoice-1042.pdf')),
]];
```

### Verify a webhook (Laravel)

```php routes/api.php theme={"dark"}
Route::post('/webhooks/sendbaze', function (Illuminate\Http\Request $request) {
    $raw = $request->getContent();
    parse_str(str_replace(',', '&', $request->header('Sendbaze-Signature', '')), $parts);
    $expected = hash_hmac('sha256', $parts['t'] . '.' . $raw, config('services.sendbaze.webhook_secret'));
    abort_unless(abs(time() - (int) $parts['t']) <= 300 && hash_equals($expected, $parts['v1'] ?? ''), 400);

    $event = json_decode($raw, true);
    // handle $event['type'] such as "email.bounced"
    return response()->json(['received' => true]);
});
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.