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

# Laravel Quickstart

> Learn how to send emails with SendPost in your Laravel application using Mailables, Notifications, and custom mail drivers

## Prerequisites

To get the most out of this guide, you'll need to:

* [**Create a SendPost Account**](https://app.sendpost.io/register)
* [**Laravel 9+**](https://laravel.com/docs)
* [**PHP 8.1+**](https://www.php.net/downloads.php)
* A **Sub-Account API Key** from your SendPost dashboard

<Info>
  You can find your API keys in your [SendPost Dashboard](https://app.sendpost.io). Make sure to use your Sub-Account API Key for sending emails.
</Info>

## 1. Install Dependencies

```shellscript composer theme={null}
composer require sendpost/sendpost-php-sdk -W
```

<Note>
  The SDK uses Guzzle 7. New Laravel 13 apps ship with Guzzle 8, and `-W` lets Composer switch them to Guzzle 7, which Laravel also supports.
</Note>

## 2. Environment Setup

Add to your `.env` file:

```env theme={null}
SENDPOST_API_KEY=your_sub_account_api_key
SENDPOST_FROM_EMAIL=hello@playwithsendpost.io
SENDPOST_FROM_NAME="SendPost"
MAIL_MAILER=sendpost
MAIL_FROM_ADDRESS=hello@playwithsendpost.io
MAIL_FROM_NAME="SendPost"
```

<Note>
  Laravel uses `MAIL_FROM_ADDRESS` and `MAIL_FROM_NAME` as the default sender for every mailable and notification.
</Note>

## 3. Create SendPost Mail Driver

Laravel 9+ sends mail through Symfony Mailer, so the driver is a Symfony transport. Create `app/Mail/Drivers/SendPostTransport.php`:

```php PHP theme={null}
<?php

namespace App\Mail\Drivers;

use sendpost\ApiException;
use sendpost\api\EmailApi;
use sendpost\Configuration;
use sendpost\model\EmailMessageObject;
use Symfony\Component\Mailer\Exception\TransportException;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\MessageConverter;

class SendPostTransport extends AbstractTransport
{
    protected EmailApi $emailApi;

    public function __construct(string $apiKey)
    {
        parent::__construct();

        $config = Configuration::getDefaultConfiguration()
            ->setApiKey('X-SubAccount-ApiKey', $apiKey);

        $this->emailApi = new EmailApi(null, $config);
    }

    protected function doSend(SentMessage $message): void
    {
        $email = MessageConverter::toEmail($message->getOriginalMessage());
        $address = fn (Address $a) => array_filter(['email' => $a->getAddress(), 'name' => $a->getName()]);

        // SendPost sends one email per `to` entry, so CC/BCC go on the first one
        $to = array_map($address, $email->getTo());
        if ($cc = $email->getCc()) {
            $to[0]['cc'] = array_map($address, $cc);
        }
        if ($bcc = $email->getBcc()) {
            $to[0]['bcc'] = array_map($address, $bcc);
        }

        $emailMessage = new EmailMessageObject();
        $emailMessage->setFrom($address($email->getFrom()[0]));
        $emailMessage->setTo($to);
        $emailMessage->setSubject($email->getSubject());

        if ($html = $email->getHtmlBody()) {
            $emailMessage->setHtmlBody($html);
        }
        if ($text = $email->getTextBody()) {
            $emailMessage->setTextBody($text);
        }
        if ($replyTo = $email->getReplyTo()) {
            $emailMessage->setReplyTo($address($replyTo[0]));
        }
        if ($attachments = $email->getAttachments()) {
            $emailMessage->setAttachments(array_map(fn ($part) => [
                'filename' => $part->getFilename(),
                'content' => base64_encode($part->getBody()),
            ], $attachments));
        }

        try {
            $responses = $this->emailApi->sendEmail($emailMessage);
        } catch (ApiException $e) {
            throw new TransportException($e->getMessage(), $e->getCode(), $e);
        }

        $message->setMessageId($responses[0]->getMessageId());
    }

    public function __toString(): string
    {
        return 'sendpost';
    }
}
```

## 4. Register Mail Driver

Add to `app/Providers/AppServiceProvider.php`:

```php PHP theme={null}
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Mail;
use App\Mail\Drivers\SendPostTransport;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        //
    }

    public function boot()
    {
        Mail::extend('sendpost', function (array $config = []) {
            return new SendPostTransport(config('services.sendpost.api_key'));
        });
    }
}
```

Add to `config/services.php`:

```php PHP theme={null}
'sendpost' => [
    'api_key' => env('SENDPOST_API_KEY'),
    'from' => [
        'email' => env('SENDPOST_FROM_EMAIL'),
        'name' => env('SENDPOST_FROM_NAME'),
    ],
],
```

Update `config/mail.php`:

```php PHP theme={null}
'mailers' => [
    // ... other mailers ...
    'sendpost' => [
        'transport' => 'sendpost',
    ],
],
```

## 5. Send Your First Email

### Using Mail Facade

```php PHP theme={null}
use Illuminate\Support\Facades\Mail;

Mail::raw('Hello, this is a test email!', function ($message) {
    $message->to('user@example.com')
            ->subject('Test Email');
});
```

### Using Mailable Class

Create a mailable:

```bash theme={null}
php artisan make:mail WelcomeEmail
```

Update `app/Mail/WelcomeEmail.php`:

```php PHP theme={null}
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class WelcomeEmail extends Mailable
{
    use Queueable, SerializesModels;

    public $user;

    public function __construct($user)
    {
        $this->user = $user;
    }

    public function build()
    {
        return $this->subject("Welcome {$this->user->first_name}!")
                    ->view('emails.welcome')
                    ->with([
                        'firstName' => $this->user->first_name,
                    ]);
    }
}
```

Create `resources/views/emails/welcome.blade.php`:

```blade Blade theme={null}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Welcome</title>
</head>
<body>
    <h1>Welcome, {{ $firstName }}!</h1>
    <p>Thank you for joining us. We're excited to have you on board.</p>
    <p>Get started by exploring our features:</p>
    <ul>
        <li>Feature 1</li>
        <li>Feature 2</li>
        <li>Feature 3</li>
    </ul>
    <p>If you have any questions, just reply to this email.</p>
    <p><a href="@{{unsubscribe}}">Unsubscribe</a></p>
</body>
</html>
```

<Tip>
  `{{unsubscribe}}` is a SendPost merge tag: SendPost replaces it with a unique [unsubscribe link](/api-reference/common-use-cases/adding-unsubscribe-links) for each recipient. The `@` stops Blade from treating it as a PHP expression.
</Tip>

Send the email:

```php PHP theme={null}
use App\Mail\WelcomeEmail;
use Illuminate\Support\Facades\Mail;

Mail::to($user->email)->send(new WelcomeEmail($user));
```

## 6. Common Use Cases

### Password Reset Email

Create `app/Mail/PasswordResetEmail.php`:

```php PHP theme={null}
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class PasswordResetEmail extends Mailable
{
    use Queueable, SerializesModels;

    public $user;
    public $resetUrl;

    public function __construct($user, $token)
    {
        $this->user = $user;
        $this->resetUrl = url("/reset-password?token={$token}");
    }

    public function build()
    {
        return $this->subject('Reset Your Password')
                    ->view('emails.password-reset')
                    ->with([
                        'firstName' => $this->user->first_name,
                        'resetUrl' => $this->resetUrl,
                    ]);
    }
}
```

Create `resources/views/emails/password-reset.blade.php`:

```blade Blade theme={null}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Reset Your Password</title>
</head>
<body>
    <h2>Hello {{ $firstName }},</h2>
    <p>We received a request to reset your password. Click the button below:</p>
    <p>
        <a href="{{ $resetUrl }}" style="background-color: #5750EC; color: white; padding: 12px 24px; text-decoration: none; border-radius: 4px; display: inline-block;">
            Reset Password
        </a>
    </p>
    <p>Or copy and paste this link: {{ $resetUrl }}</p>
    <p>This link will expire in 1 hour.</p>
    <p>If you didn't request this, please ignore this email.</p>
</body>
</html>
```

### Order Confirmation Email

Create `app/Mail/OrderConfirmation.php`:

```php PHP theme={null}
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class OrderConfirmation extends Mailable
{
    use Queueable, SerializesModels;

    public $order;
    public $user;

    public function __construct($order, $user)
    {
        $this->order = $order;
        $this->user = $user;
    }

    public function build()
    {
        return $this->subject("Order {$this->order->id} Confirmed")
                    ->view('emails.order-confirmation')
                    ->with([
                        'order' => $this->order,
                        'user' => $this->user,
                    ]);
    }
}
```

## 7. Using Notifications

Create a notification:

```bash theme={null}
php artisan make:notification WelcomeNotification
```

Update `app/Notifications/WelcomeNotification.php`:

```php PHP theme={null}
<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;

class WelcomeNotification extends Notification
{
    use Queueable;

    public function via($notifiable)
    {
        return ['mail'];
    }

    public function toMail($notifiable)
    {
        return (new MailMessage)
                    ->subject("Welcome {$notifiable->first_name}!")
                    ->view('emails.welcome', [
                        'firstName' => $notifiable->first_name,
                    ]);
    }
}
```

Send notification:

```php PHP theme={null}
$user->notify(new WelcomeNotification());
```

## 8. Personalization with Custom Fields

Create a custom mailable with personalization:

```php PHP theme={null}
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class PersonalizedEmail extends Mailable
{
    use Queueable, SerializesModels;

    public $recipient;
    public $customFields;

    public function __construct($recipient, $customFields = [])
    {
        $this->recipient = $recipient;
        $this->customFields = $customFields;
    }

    public function build()
    {
        // For SendPost personalization, you'll need to use the API directly
        // or extend the transport to handle customFields
        return $this->subject('Personalized Email')
                    ->view('emails.personalized')
                    ->with($this->customFields);
    }
}
```

## 9. Direct API Usage (Alternative)

Create `app/Services/SendPostService.php`:

```php PHP theme={null}
<?php

namespace App\Services;

use sendpost\api\EmailApi;
use sendpost\model\EmailMessageObject;
use sendpost\Configuration;

class SendPostService
{
    protected $apiKey;
    protected $fromEmail;
    protected $fromName;

    public function __construct()
    {
        $this->apiKey = config('services.sendpost.api_key');
        $this->fromEmail = config('services.sendpost.from.email');
        $this->fromName = config('services.sendpost.from.name');
    }

    public function sendEmail($to, $subject, $htmlBody, $textBody = null, $customFields = [])
    {
        $config = Configuration::getDefaultConfiguration();
        $config->setApiKey('X-SubAccount-ApiKey', $this->apiKey);
        $config->setHost('https://api.sendpost.io/api/v1');

        $emailApi = new EmailApi(null, $config);
        $emailMessage = new EmailMessageObject();

        $emailMessage->setFrom([
            'email' => $this->fromEmail,
            'name' => $this->fromName
        ]);

        $recipients = [];
        if (is_string($to)) {
            $recipients[] = [
                'email' => $to,
                'customFields' => $customFields
            ];
        } else {
            foreach ($to as $email => $name) {
                $recipients[] = [
                    'email' => $email,
                    'name' => $name,
                    'customFields' => $customFields
                ];
            }
        }

        $emailMessage->setTo($recipients);
        $emailMessage->setSubject($subject);
        $emailMessage->setHtmlBody($htmlBody);
        
        if ($textBody) {
            $emailMessage->setTextBody($textBody);
        }

        try {
            $responses = $emailApi->sendEmail($emailMessage); // one EmailResponse per recipient
            return ['success' => true, 'message_ids' => array_map(fn ($r) => $r->getMessageId(), $responses)];
        } catch (\Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
}
```

Use the service:

```php PHP theme={null}
use App\Services\SendPostService;

$sendPostService = new SendPostService();
$result = $sendPostService->sendEmail(
    'user@example.com',
    'Welcome {{firstName}}!',
    '<h1>Welcome, {{firstName}}!</h1>',
    'Welcome, {{firstName}}!',
    ['firstName' => 'John']
);
```

<Warning>
  Make sure your sender email domain is verified in your SendPost account before sending emails.
</Warning>

## 10. Next Steps

Explore more examples and use cases:

<Columns cols={3}>
  <Card title="Laravel Documentation" icon="laravel" href="https://laravel.com/docs">
    Learn more about Laravel framework
  </Card>

  <Card title="SendPost PHP SDK" icon="php" href="https://github.com/sendpost/sendpost-php-sdk">
    View the official SDK on GitHub
  </Card>

  <Card title="Quickstart Example" icon="github" href="https://github.com/sendpost/sendpost-laravel-example">
    View a complete working example on GitHub
  </Card>
</Columns>


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