unsent
unsent.dev
Guides

Laravel

How to send emails with Unsent in Laravel

This guide shows how to install and use the official Unsent PHP SDK in a Laravel application.

Installation

Install the SDK via Composer. Run the following command in your Laravel project directory:

composer require souravsspace/unsent

Configure API Key

Add your Unsent API key to your .env file:

.env
UNSENT_API_KEY=un_xxx

Initialize the Client

You can initialize the Unsent client in multiple ways in Laravel.

Option 1: Direct Initialization

<?php

use Souravsspace\Unsent\Unsent;

$client = new Unsent(env('UNSENT_API_KEY'));

Option 2: Using a Service Provider

Create a service provider to register the Unsent client as a singleton:

php artisan make:provider UnsentServiceProvider
app/Providers/UnsentServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Souravsspace\Unsent\Unsent;

class UnsentServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(Unsent::class, function ($app) {
            return new Unsent(config('services.unsent.api_key'));
        });
    }
}

Add the provider to config/app.php:

config/app.php
'providers' => [
    // ...
    App\Providers\UnsentServiceProvider::class,
],

And add the configuration to config/services.php:

config/services.php
'unsent' => [
    'api_key' => env('UNSENT_API_KEY'),
],

Send an Email

Now you can send emails. The SDK methods return a tuple [$data, $error]. You should always check if $error is present to handle any issues.

Here's an example in a controller:

<?php

namespace App\Http\Controllers;

use Souravsspace\Unsent\Unsent;

class EmailController extends Controller
{
    public function send(Unsent $client)
    {
        [$data, $error] = $client->emails->send([
            'to' => 'user@example.com',
            'from' => 'no-reply@yourdomain.com',
            'subject' => 'Welcome to Our App',
            'html' => '<strong>Hello from Laravel!</strong>',
            'headers' => ['X-Campaign' => 'welcome'],
        ]);

        if ($error) {
            return response()->json(['error' => $error['message']], 500);
        }

        return response()->json(['emailId' => $data['emailId']]);
    }
}

Or in a route:

routes/web.php
use Illuminate\Support\Facades\Route;
use Souravsspace\Unsent\Unsent;

Route::get('/send-email', function (Unsent $client) {
    [$data, $error] = $client->emails->send([
        'to' => 'user@example.com',
        'from' => 'no-reply@yourdomain.com',
        'subject' => 'Hello from Laravel',
        'html' => '<h1>It works!</h1>',
    ]);

    if ($error) {
        return response()->json(['error' => $error['message']], 500);
    }

    return response()->json($data);
});

Note

Unsent forwards your custom headers to SES. Only the X-Unsent-Email-ID and References headers are managed automatically by Unsent.

Advanced Email Features

Attachments and Scheduling

You can send emails with attachments and schedule them for later delivery.

<?php

use DateTime;

[$data, $error] = $client->emails->send([
    'to' => ['user1@example.com', 'user2@example.com'],
    'from' => 'no-reply@yourdomain.com',
    'subject' => 'Monthly Report',
    'text' => 'Please see the attached report.',
    'attachments' => [
        [
            'filename' => 'report.pdf',
            'content' => base64_encode(file_get_contents(storage_path('reports/monthly.pdf'))),
        ],
    ],
    'scheduledAt' => new DateTime('+1 hour'), // Schedule for 1 hour from now
]);

Batch Send

Send multiple emails efficiently in a single request:

<?php

$emails = [
    [
        'to' => 'alice@example.com',
        'from' => 'no-reply@yourdomain.com',
        'subject' => 'Welcome Alice',
        'html' => '<p>Welcome, Alice!</p>',
    ],
    [
        'to' => 'bob@example.com',
        'from' => 'no-reply@yourdomain.com',
        'subject' => 'Welcome Bob',
        'html' => '<p>Welcome, Bob!</p>',
    ],
];

[$data, $error] = $client->emails->batch($emails);

Idempotent Retries

Use idempotency keys to safely retry requests:

<?php

// For single email
$client->emails->send($email, ['idempotencyKey' => 'unique-key-' . $userId]);

// For batch emails
$client->emails->batch($emails, ['idempotencyKey' => 'batch-' . now()->timestamp]);

Email Management

Get an Email

Fetch the status and details of a specific email:

<?php

[$email, $error] = $client->emails->get($emailId);

if ($email) {
    echo "Status: {$email['status']}";
}

Update Scheduled Email

Change the scheduled delivery time:

<?php

use DateTime;

[$data, $error] = $client->emails->update($emailId, [
    'scheduledAt' => new DateTime('+2 hours'),
]);

Cancel a Scheduled Email

<?php

[$data, $error] = $client->emails->cancel($emailId);

List Emails

<?php

[$data, $error] = $client->emails->list([
    'page' => 1,
    'limit' => 50,
    'startDate' => '2024-01-01T00:00:00Z',
    'endDate' => '2024-12-31T23:59:59Z',
    'domainId' => 'domain_123'
]);

if (!$error) {
    foreach ($data['data'] as $email) {
        echo "Email ID: {$email['id']}, Status: {$email['status']}\n";
    }
}

Get Email Events

<?php

[$data, $error] = $client->emails->getEvents($emailId, [
    'page' => 1,
    'limit' => 50
]);

if (!$error) {
    foreach ($data as $event) {
        echo "Event: {$event['type']} at {$event['timestamp']}\n";
    }
}

Contacts

Manage your contacts and organize them into contact books.

Create a Contact

<?php

[$data, $error] = $client->contacts->create($bookId, [
    'email' => 'user@example.com',
    'firstName' => 'Jane',
    'properties' => ['plan' => 'pro'],
]);

Get a Contact

<?php

[$contact, $error] = $client->contacts->get($bookId, $contactId);

Update a Contact

<?php

[$data, $error] = $client->contacts->update($bookId, $contactId, [
    'subscribed' => false,
    'properties' => ['status' => 'inactive'],
]);

Upsert a Contact

Create if doesn't exist, update if exists:

<?php

[$data, $error] = $client->contacts->upsert($bookId, $contactId, [
    'email' => 'user@example.com',
    'firstName' => 'Jane',
]);

Delete a Contact

<?php

[$data, $error] = $client->contacts->delete($bookId, $contactId);

Contact Books

Organize your contacts into groups.

List Contact Books

<?php

[$data, $error] = $client->contactBooks->list();

if (!$error) {
    foreach ($data as $book) {
        echo "Book: {$book['name']}\n";
    }
}

Create a Contact Book

<?php

[$data, $error] = $client->contactBooks->create([
    'name' => 'Newsletter Subscribers',
    'emoji' => '📧'
]);

Get a Contact Book

<?php

[$data, $error] = $client->contactBooks->get($bookId);

Update a Contact Book

<?php

[$data, $error] = $client->contactBooks->update($bookId, [
    'name' => 'Updated Newsletter List',
]);

Delete a Contact Book

<?php

[$data, $error] = $client->contactBooks->delete($bookId);

Campaigns

Send emails to all contacts in a contact book.

Create a Campaign

<?php

[$data, $error] = $client->campaigns->create([
    'name' => 'Welcome Series',
    'from' => 'welcome@yourdomain.com',
    'subject' => 'Welcome to our service!',
    'html' => '<p>Thanks for joining us!</p>',
    'contactBookId' => $bookId,
]);

Get a Campaign

<?php

[$campaign, $error] = $client->campaigns->get($campaignId);

Schedule a Campaign

<?php

[$data, $error] = $client->campaigns->schedule($campaignId, [
    'scheduledAt' => '2024-12-01T10:00:00Z',
]);

Pause/Resume a Campaign

<?php

// Pause
[$data, $error] = $client->campaigns->pause($campaignId);

// Resume
[$data, $error] = $client->campaigns->resume($campaignId);

Domains

Manage your sending domains.

List Domains

<?php

[$domains, $error] = $client->domains->list();

if (!$error) {
    foreach ($domains as $domain) {
        echo "Domain: {$domain['name']}, Status: {$domain['status']}\n";
    }
}

Create a Domain

<?php

[$data, $error] = $client->domains->create([
    'name' => 'yourdomain.com',
    'region' => 'us-east-1',
]);

Verify a Domain

<?php

[$data, $error] = $client->domains->verify($domainId);

Get a Domain

<?php

[$domain, $error] = $client->domains->get($domainId);

Delete a Domain

<?php

[$data, $error] = $client->domains->delete($domainId);

Domain Analytics

<?php

[$data, $error] = $client->domains->getAnalytics($domainId, [
    'days' => 30
]);

Domain Stats

<?php

[$data, $error] = $client->domains->getStats($domainId);

Templates

Create reusable email templates with variable placeholders.

List Templates

<?php

[$data, $error] = $client->templates->list();

if (!$error) {
    foreach ($data as $template) {
        echo "Template: {$template['name']}\n";
    }
}

Create a Template

<?php

[$data, $error] = $client->templates->create([
    'name' => 'Welcome Email',
    'subject' => 'Welcome to {{company}}!',
    'html' => '<h1>Welcome, {{firstName}}!</h1>',
]);

Get a Template

<?php

[$data, $error] = $client->templates->get($templateId);

Update a Template

<?php

[$data, $error] = $client->templates->update($templateId, [
    'subject' => 'Updated Subject Line',
]);

Delete a Template

<?php

[$data, $error] = $client->templates->delete($templateId);

Analytics

Get insights into your email performance.

Get Analytics Overview

<?php

[$data, $error] = $client->analytics->get();

if (!$error) {
    echo "Sent: {$data['sent']}\n";
    echo "Delivered: {$data['delivered']}\n";
    echo "Bounced: {$data['bounced']}\n";
}

Get Time Series Data

<?php

[$data, $error] = $client->analytics->getTimeSeries(['days' => 30]);

if (!$error) {
    foreach ($data as $point) {
        echo "Date: {$point['date']}, Sent: {$point['sent']}\n";
    }
}

Get Reputation Score

<?php

[$data, $error] = $client->analytics->getReputation();

if (!$error) {
    echo "Reputation Score: {$data['score']}\n";
}

API Keys

Manage API keys for your application.

List API Keys

<?php

[$data, $error] = $client->apiKeys->list();

if (!$error) {
    foreach ($data as $key) {
        echo "Key: {$key['name']}\n";
    }
}

Create an API Key

<?php

[$data, $error] = $client->apiKeys->create([
    'name' => 'Production Key',
    'permission' => 'SENDING'
]);

if (!$error) {
    // Important: Save this token securely
    echo "New API Key: {$data['token']}\n";
}

Delete an API Key

<?php

[$data, $error] = $client->apiKeys->delete($keyId);

Settings

Get your account settings.

<?php

[$data, $error] = $client->settings->get();

if (!$error) {
    echo "Account: {$data['accountName']}\n";
}

Suppressions

Manage your suppression list to prevent emails from being sent to certain addresses.

List Suppressions

<?php

[$data, $error] = $client->suppressions->list([
    'page' => 1,
    'limit' => 50
]);

if (!$error) {
    foreach ($data['data'] as $suppression) {
        echo "Email: {$suppression['email']}, Reason: {$suppression['reason']}\n";
    }
}

Add a Suppression

<?php

[$data, $error] = $client->suppressions->add([
    'email' => 'user@example.com',
    'reason' => 'MANUAL'
]);

Delete a Suppression

<?php

[$data, $error] = $client->suppressions->delete('user@example.com');

Webhooks

Future Feature

Webhooks are included in the SDK for reference as a future implementation. The webhook functionality is not yet fully operational in the API.

List Webhooks

<?php

[$data, $error] = $client->webhooks->list();

Create a Webhook

<?php

[$data, $error] = $client->webhooks->create([
    'url' => 'https://your-app.test/webhook',
    'events' => ['email.sent', 'email.delivered']
]);

Update a Webhook

<?php

[$data, $error] = $client->webhooks->update($webhookId, [
    'url' => 'https://your-app.test/updated-webhook',
]);

Delete a Webhook

<?php

[$data, $error] = $client->webhooks->delete($webhookId);

System Operations

Check API health and get version information.

Health Check

<?php

[$data, $error] = $client->system->health();

if (!$error) {
    echo "API Status: {$data['status']}\n";
    echo "Uptime: {$data['uptime']} seconds\n";
}

Get Version Information

<?php

[$data, $error] = $client->system->version();

if (!$error) {
    echo "API Version: {$data['version']}\n";
    echo "Environment: {$data['environment']}\n";
}

Activity Feed

Retrieve your activity feed with email events and details.

<?php

[$data, $error] = $client->activity->get([
    'page' => 1,
    'limit' => 50
]);

Events

List and filter email events.

List All Events

<?php

[$data, $error] = $client->events->list([
    'page' => 1,
    'limit' => 50,
    'status' => 'DELIVERED',
    'startDate' => '2024-01-01T00:00:00Z'
]);

Teams

Manage team information.

List Teams

<?php

[$data, $error] = $client->teams->list();

if (!$error) {
    foreach ($data as $team) {
        echo "Team: {$team['name']}\n";
    }
}

Get Team Details

<?php

[$data, $error] = $client->teams->get($teamId);

if (!$error) {
    echo "Team Name: {$data['name']}\n";
    echo "Plan: {$data['plan']}\n";
}

Metrics & Stats

Retrieve metrics and statistical data for your account.

Get Metrics

<?php

[$data, $error] = $client->metrics->get();

Get Stats

<?php

[$data, $error] = $client->stats->get();

Error Handling

The SDK supports two modes of error handling.

Raising Exceptions (Default)

By default, the SDK raises UnsentHTTPError exceptions for non-2xx responses:

<?php

use Souravsspace\Unsent\Unsent;
use Souravsspace\Unsent\UnsentHTTPError;

$client = new Unsent(env('UNSENT_API_KEY'));

try {
    [$data, $_] = $client->emails->get($emailId);
    return response()->json($data);
} catch (UnsentHTTPError $e) {
    \Log::error("Unsent API Error: HTTP {$e->statusCode} - {$e->error['message']}");
    return response()->json(['error' => $e->error['message']], $e->statusCode);
}

Returning Error Tuples

If you prefer to handle errors as return values without exceptions:

<?php

// Pass false as the third argument to disable exceptions
$client = new Unsent(env('UNSENT_API_KEY'), null, false);

[$data, $error] = $client->emails->get($emailId);

if ($error) {
    return response()->json(['error' => $error['message']], 500);
}

return response()->json($data);

Using Laravel SMTP Driver

Alternatively, you can use Laravel's built-in SMTP driver instead of the SDK:

.env
MAIL_MAILER=smtp
MAIL_HOST=smtp.unsent.dev
MAIL_PORT=587
MAIL_USERNAME=unsent
MAIL_PASSWORD=un_xxx
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="no-reply@yourdomain.com"
MAIL_FROM_NAME="${APP_NAME}"

Then use Laravel's Mail facade:

<?php

use Illuminate\Support\Facades\Mail;

Mail::raw('Hello from Laravel!', function ($message) {
    $message->to('user@example.com')
            ->subject('Test Email');
});

Resources