resend/resend-laravel
Resend integration for Laravel and Symfony Mailer. Send emails via the Resend API using a simple facade, or switch to the bundled Laravel mailer transport. Configure your RESEND_API_KEY and set MAIL_MAILER=resend to get started.
Installation
composer require resend/resend-laravel
Ensure your project uses PHP 8.1+ and Laravel 10.x+ (or 11.x+).
Configure API Key
Add your Resend API key to .env:
RESEND_API_KEY=re_123456789
First Email (Direct API Call)
Use the Resend facade to send a simple email:
use Resend\Laravel\Facades\Resend;
Resend::emails()->send([
'from' => 'onboarding@resend.dev',
'to' => 'user@example.com',
'subject' => 'Hello from Resend!',
'html' => '<p>This is a test email.</p>',
]);
Laravel Mailer Integration
Configure config/mail.php:
'resend' => [
'transport' => 'resend',
],
Update .env:
MAIL_MAILER=resend
Now use Laravel’s Mail facade as usual:
Mail::to('user@example.com')->send(new WelcomeEmail());
Direct API Calls (for non-Mailable use cases):
Resend::emails()->send([
'from' => 'team@yourdomain.com',
'to' => ['user1@example.com', 'user2@example.com'],
'subject' => 'Your Order Confirmation',
'html' => view('emails.order', ['order' => $order]),
'attachments' => [
['filename' => 'invoice.pdf', 'content' => file_get_contents('path/to/invoice.pdf')],
],
'headers' => ['X-Custom-Header' => 'value'],
]);
send(): Send immediately.create(): Prepare a draft (useful for queuing).sendLater(): Schedule for later (requires resend/resend-php v1+).Laravel Mailable Integration:
Extend Laravel’s Mailable class and attach files:
public function build()
{
return $this->subject('Welcome!')
->markdown('emails.welcome')
->with(['name' => $user->name])
->attach('path/to/file.pdf', [
'as' => 'document.pdf',
'mime' => 'application/pdf',
]);
}
app/Http/Kernel.php:
protected $middleware = [
// ...
\Resend\Laravel\Http\Middleware\VerifyWebhookSignature::class,
];
Route::post('/resend-webhook', [ResendWebhookController::class, 'handle']);
public function handle(Request $request)
{
$event = Resend::webhooks()->parse($request->getContent());
// Handle event (e.g., email.delivered, contact.created)
return response()->json(['status' => 'success']);
}
Resend::emails()->send([
'from' => 'team@yourdomain.com',
'to' => 'user@example.com',
'subject' => 'Newsletter',
'html' => '<p>Monthly update</p>',
'tags' => ['marketing', 'newsletter'],
'idempotency_key' => 'unique-key-123', // Prevent duplicate sends
]);
Resend::emails()->send([
'from' => 'team@yourdomain.com',
'to' => 'user@example.com',
'html' => '<p><img src="cid:logo" /></p>',
'attachments' => [
[
'filename' => 'logo.png',
'content' => file_get_contents('path/to/logo.png'),
'content_id' => 'logo', // Matches `cid:` in HTML
],
],
]);
Use Laravel’s queue system with the Resend mailer:
Mail::to('user@example.com')->queue(new WelcomeEmail());
php artisan queue:work to process emails asynchronously.Environment-Specific Configs: Publish the config file for customization:
php artisan vendor:publish --tag="resend"
Modify config/resend.php for:
from address.Testing:
Resend::emails()->mock() to intercept calls in tests:
Resend::emails()->mock()
->shouldReceive('send')
->once()
->withArgs([...]);
$event = Resend::webhooks()->parse($rawPayload);
$this->assertEquals('email.delivered', $event->type);
Error Handling: Wrap API calls in try-catch:
try {
Resend::emails()->send([...]);
} catch (\Resend\Exceptions\ResendException $e) {
Log::error('Resend error: ' . $e->getMessage());
// Retry or notify admin
}
API Key Exposure:
.env to version control. Use Laravel’s .env.example for templates.Attachment Size Limits:
if ($file->getSize() > 30 * 1024 * 1024) {
throw new \Exception('File too large for Resend.');
}
Webhook Delays:
$attempts = 0;
while ($attempts < 3) {
try {
$event = Resend::webhooks()->parse($payload);
break;
} catch (\Exception $e) {
$attempts++;
sleep(2 ** $attempts); // Exponential backoff
}
}
HTML Email Rendering:
$html = Premailer::instance()->transform($html);
Idempotency Key Conflicts:
idempotency_key for duplicate sends may silently fail. Generate unique keys for critical emails:
$idempotencyKey = Str::uuid()->toString();
Enable Resend Debugging:
Add to .env:
RESEND_DEBUG=true
Logs will include request/response payloads for troubleshooting.
Inspect Raw API Calls: Use Laravel’s logging to dump the payload before sending:
$payload = [
'from' => '...',
'to' => '...',
// ...
];
Log::debug('Resend payload', $payload);
Resend::emails()->send($payload);
Webhook Signature Verification: If webhooks fail with signature errors:
RESEND_WEBHOOK_SECRET in .env matches Resend’s dashboard.Resend-Signature header.Rate Limiting: Resend enforces rate limits (~1,000 emails/hour for free tier). Monitor usage via:
$usage = Resend::usage()->get();
Log::info('Resend usage:', $usage->toArray());
ResendTransport class to add domain-specific logic:
namespace App\Mail\Transports;
use Resend\Laravel\Transports\ResendTransport;
class CustomResendTransport extends ResendTransport
How can I help you explore Laravel packages today?