async-aws/ses
AsyncAws SES is a lightweight PHP client for Amazon Simple Email Service. Install via Composer and send emails or manage SES resources with a modern, typed API and async-friendly design. Full docs available at async-aws.com/clients/ses.html.
composer require async-aws/ses
.env:
AWS_ACCESS_KEY_ID=your_key
AWS_SECRET_ACCESS_KEY=your_secret
AWS_DEFAULT_REGION=us-east-1 # or your preferred region
use AsyncAws\Ses\SesClient;
use AsyncAws\Ses\ValueObject\Destination;
use AsyncAws\Ses\ValueObject\Content;
$ses = new SesClient();
$response = $ses->sendEmail([
'Destination' => new Destination(['ToAddresses' => ['user@example.com']]),
'Content' => new Content([
'Simple' => [
'Subject' => ['Data' => 'Test Email'],
'Body' => ['Text' => ['Data' => 'Hello from SES!']],
],
]),
]);
Replace Laravel’s default Mail facade with a queueable SES sender:
// app/Providers/AppServiceProvider.php
public function boot()
{
Mail::extend('ses', function ($app) {
return new class extends Mailer {
public function send(Mailable $mailable, Address $to)
{
$ses = new SesClient();
$response = $ses->sendEmail([
'Destination' => new Destination(['ToAddresses' => [$to->email]]),
'Content' => new Content([
'Simple' => [
'Subject' => ['Data' => $mailable->subject],
'Body' => ['Text' => ['Data' => $mailable->content]],
],
]),
]);
return new MailMessage($response);
}
};
});
}
Use it in your app:
Mail::ses()->to('user@example.com')->send(new OrderConfirmation($order));
Leverage Laravel’s queue system for non-blocking email delivery:
// Dispatch a queued email
Mail::ses()->to('user@example.com')->send(new WelcomeEmail($user))
->afterCommit(); // Ensures email is sent after DB commit
Queue configuration (config/queue.php):
'connections' => [
'ses' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'ses_emails',
'after_commit' => true,
],
],
Use SESv2’s template system for reusable content:
// Store a template in AWS SES Console first
$ses = new SesClient();
$response = $ses->sendEmail([
'FromEmailAddress' => 'noreply@example.com',
'Destination' => new Destination(['ToAddresses' => ['user@example.com']]),
'Content' => new Content([
'Template' => [
'TemplateName' => 'welcome_template',
'TemplateData' => json_encode(['name' => $user->name]),
],
]),
]);
Send to multiple recipients efficiently:
$ses = new SesClient();
$response = $ses->sendBulkEmail([
'FromEmailAddress' => 'noreply@example.com',
'Destination' => new Destination(['ToAddresses' => ['user1@example.com', 'user2@example.com']]),
'Content' => new Content([
'Simple' => [
'Subject' => ['Data' => 'Bulk Update'],
'Body' => ['Text' => ['Data' => 'Hello, users!']],
],
]),
]);
Add files to emails (SESv2 feature):
$ses = new SesClient();
$response = $ses->sendEmail([
'FromEmailAddress' => 'noreply@example.com',
'Destination' => new Destination(['ToAddresses' => ['user@example.com']]),
'Content' => new Content([
'Simple' => [
'Subject' => ['Data' => 'Invoice'],
'Body' => ['Text' => ['Data' => 'Please find your invoice attached.']],
],
]),
'Attachments' => [
[
'Data' => base64_encode(file_get_contents('invoice.pdf')),
'Name' => 'invoice.pdf',
'ContentType' => 'application/pdf',
],
],
]);
Add headers for tracking or custom logic:
$ses = new SesClient();
$response = $ses->sendEmail([
'FromEmailAddress' => 'noreply@example.com',
'Destination' => new Destination(['ToAddresses' => ['user@example.com']]),
'Content' => new Content([
'Simple' => [
'Subject' => ['Data' => 'Tracking Header'],
'Body' => ['Text' => ['Data' => 'Check headers!']],
],
]),
'Headers' => [
['Name' => 'X-Custom-ID', 'Value' => 'order_12345'],
['Name' => 'X-Tracking', 'Value' => 'marketing_campaign'],
],
]);
Wrap SES calls in try-catch blocks:
use AsyncAws\Core\Exception\AwsException;
try {
$response = $ses->sendEmail([/* ... */]);
} catch (AwsException $e) {
Log::error('SES Error: ' . $e->getAwsErrorMessage());
// Retry logic or fallback to another provider
}
Configure region-specific clients:
$euSes = new SesClient(['region' => 'eu-west-1']);
$usSes = new SesClient(['region' => 'us-east-1']);
// Send region-specific emails
$euSes->sendEmail([/* ... */]);
$usSes->sendEmail([/* ... */]);
Manage bounced/complaint lists:
// Add a suppressed destination
$ses->setSuppressedDestination([
'Destination' => 'user@example.com',
'Reason' => 'Complaint',
]);
// Delete a suppressed destination
$ses->deleteSuppressedDestination([
'Destination' => 'user@example.com',
]);
AWS SES Sandbox Restrictions:
verifyEmailIdentity() to verify addresses programmatically:
$ses->verifyEmailIdentity(['EmailAddress' => 'user@example.com']);
Quota Limits:
SendQuotaExceeded exceptions and adjust limits in AWS Console or use exponential backoff in retries.Attachment Size Limits:
DKIM Misconfiguration:
Region-Specific Features:
fips-* regions) require specific configurations.Async Delays:
Mail::later() for time-sensitive emails or switch to sync SES calls for critical paths.PHP 8.2+ Requirement:
1.13.*).Null Values in Inputs:
null (e.g., ['ReplyToAddresses' => null]).null to override default values in SES requests.Enable AWS SDK Debugging:
Add to .env:
AWS_DEBUG=true
Or configure the client:
$ses = new SesClient(['debug' => true]);
Log SES Responses:
$response = $ses->sendEmail([/* ... */]);
Log::debug('SES Response', ['response' => $response->toArray()]);
Validate Inputs:
Use Input\* classes to ensure valid payloads:
use AsyncAws\Ses\Input\SendEmailRequest;
$input =
How can I help you explore Laravel packages today?