How to send Laravel email using Unsend.
I’ve been using Unsend all over the place now that I’m self-hosting it.
In my Laravel apps I’d started out using a generic SMTP connection before realizing a simple custom transport could connect with the Unsend API directly.
The documentation was straightforward, and the bulk of the effort was mapping Laravel’s message details to a suitable API payload and testing it.
I started by creating app/Mail/Transports/UnsendTransport.php:
<?php
namespace App\Mail\Transports;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Uri;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Tran...
How to send Laravel email using Unsend.
I’ve been using Unsend all over the place now that I’m self-hosting it.
In my Laravel apps I’d started out using a generic SMTP connection before realizing a simple custom transport could connect with the Unsend API directly.
The documentation was straightforward, and the bulk of the effort was mapping Laravel’s message details to a suitable API payload and testing it.
I started by creating app/Mail/Transports/UnsendTransport.php:
<?php
namespace App\Mail\Transports;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Uri;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\MessageConverter;
use Symfony\Component\Mime\Part\DataPart;
class UnsendTransport extends AbstractTransport
{
/**
* {@inheritDoc}
*/
protected function doSend(SentMessage $message): void
{
$email = MessageConverter::toEmail($message->getOriginalMessage());
$apiKey = env('UNSEND_API_KEY');
$baseUrl = Uri::to('/')
->withHost(env('UNSEND_DOMAIN'))
->withScheme('https')
->value();
if ($from = collect($email->getFrom())->first()) {
$fromValue = $from->toString();
}
$postBody = [
'to' => collect($email->getTo())->map(function (Address $email) {
return $email->toString();
})->toArray(),
'from' => $fromValue ?? null,
'subject' => $email->getSubject(),
'replyTo' => collect($email->getReplyTo())->map(function (Address $email) {
return $email->getAddress();
})->toArray(),
'cc' => collect($email->getCc())->map(function (Address $email) {
return $email->toString();
})->toArray(),
'bcc' => collect($email->getBcc())->map(function (Address $email) {
return $email->toString();
})->toArray(),
'text' => $email->getTextBody(),
'html' => $email->getHtmlBody(),
'attachments' => collect($email->getAttachments())->map(function (DataPart $part) {
return [
'filename' => $part->getFilename(),
'content' => base64_encode($part->getBody()),
];
})->toArray(),
];
Http::withHeaders([
'Content-Type' => 'application/json',
'Authorization' => 'Bearer '.$apiKey,
])
->baseUrl($baseUrl)
->post('/api/v1/emails', $postBody);
}
/**
* Get the string representation of the transport.
*/
public function __toString(): string
{
return 'unsend';
}
}
This needs to be registered in app/providers/AppServiceProvider.php:
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// ...
Mail::extend('unsend', static function () {
return new \App\Mail\Transports\UnsendTransport;
});
}
You can then define a mailer in config/mail.php:
// ...
'mailers' => [
'unsend' => [
'transport' => 'unsend',
],
],
Finally, designate the mailer and add your API credentials:
MAIL_MAILER=unsend
UNSEND_API_KEY=us_•••••••••••••••••••••••••••••••••••••••••••
UNSEND_DOMAIN=unsend.example.com
You can see if it works by opening a Tinker shell with php artisan tinker, then using the Mail facade to send a quick test:
Mail::raw('Hi!', function($m) { $m->to('me@example.com')->subject('Test Email'); });