Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Illuminate Mail Laravel Package

async-aws/illuminate-mail

Integrates AsyncAws with Laravel's Illuminate Mail, adding an SES mail transport so Laravel apps can send email through AWS using the lightweight AsyncAws client instead of the official AWS SDK. Simple mailer configuration with no heavy SDK dependency.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the transport and let package auto-discovery register the service provider:

composer require async-aws/illuminate-mail:0.1.5

Pin the exact version — this is 0.1.x and archived since 2023-08-07, so no future patch will fix an accidental breaking composer update.

Configure a mailer in config/mail.php. The transport is exposed as the async-aws mailer driver, so a typical setup is:

'mailers' => [
    'ses' => [
        'transport' => 'async-aws',
    ],
],

Credentials come from the standard AsyncAws environment variables, which are the same shape as the AWS CLI:

MAIL_MAILER=ses
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_DEFAULT_REGION=eu-west-1

Before sending a single email, do these four things in order:

  1. Read the source. This package has no documentation beyond its README and a changelog pointer. The transport class is small — open it and confirm which config keys it reads (services.ses.* vs env only) and whether it instantiates SendEmail or SendRawEmail by default. That thirty minutes replaces a day of guessing.
  2. Verify your SES domain / sender in the target region. SES is regional — eu-west-1 and us-east-1 do not share verification.
  3. Check your IAM policy grants ses:SendEmail and ses:SendRawEmail. The AsyncAws SES client uses the same permission surface as the full SDK.
  4. Leave the sandbox. New SES accounts can only send to verified recipients until production access is granted. This is the single most common cause of "the driver works but nothing arrives."

Your first use case is almost certainly transactional mail through a Mailable:

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

Nothing about this call is package-specific — that is the point. The transport swaps in under Illuminate\Mail.

Implementation Patterns

Everything routes through Illuminate Mail. Mailables, Notifications with the mail channel, Mail::raw, and queued mail (ShouldQueue) all work unchanged because the package only supplies a transport; the rest of the stack — queueing, templating, view rendering — is untouched. This is the package's main day-to-day advantage: existing mail code stays as-is.

Use it as a non-default mailer during migration. Keep log or array as the local default and register async-aws as a named mailer:

Mail::mailer('ses')->to($user)->send(new InvoiceMail($invoice));

This lets you canary the transport on a subset of mailers (receipts, internal alerts) before flipping MAIL_MAILER globally.

Queue the send, not the transport. Since queued mail goes through Illuminate\Mail\SendQueuedMailable, the transport is only hit on the worker. If you are seeing intermittent SES rate-limit errors, the fix is Laravel's ShouldQueue + a rate-limited queue (RateLimited, mail rate limiter), not a change to the transport.

Raw vs simple send. The package supports both SendEmail and SendRawEmail. Simple sends are cheaper and easier to debug but cannot carry attachments or custom headers; raw sends give you MIME control at the cost of having to render headers yourself. For anything with an attachment (invoices, signed PDFs), you want the raw path — confirm which one the transport chooses for your message shape by reading the source or logging the AsyncAws response.

Testing is free. Because the driver sits behind Mail::fake(), existing mail tests keep working with zero changes. Write a transport-level test only if you want to assert SES request shape — otherwise Mail::assertSent(WelcomeEmail::class) is sufficient.

Adapter boundary. Wrap the transport configuration, not the Mail facade. The only place that should know this package exists is config/mail.php plus, if you want an exit hatch, a small MailerFactory that returns async-aws when MAIL_TRANSPORT=ses is set. When you switch to Laravel's built-in ses driver (added in Laravel 9), the change is one config line and one composer remove.

Gotchas and Tips

The package is archived — plan the exit before you plan the feature. No future Laravel minor version is guaranteed to work with it. Laravel 11/12 removed or reshaped several mailer internals; assume breakage on the next major upgrade. Mitigations, in order of preference: (a) use Laravel's first-party ses driver — same SES, one fewer dependency, and you already have aws/aws-sdk-php if you need it elsewhere; (b) if you specifically want the AsyncAws dependency footprint, fork the package into packages/ and vendor it; (c) do not adopt on a greenfield project without a fork plan.

Credential resolution order is the sharpest gotcha. AsyncAws honors AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, then ~/.aws/credentials, then IAM instance profiles. In a Laravel app that also touches S3, SQS, or SNS, one set of env vars serves all of them — a test-only key for SES will silently break other AWS calls, or vice versa. Prefer a dedicated services.ses config block if the transport supports it; if not, document the environment contract loudly.

Region must match the verified identity. A message sent from us-east-1 to an identity verified in eu-west-1 fails with MessageRejected: Email address not verified — the error reads like a credentials problem, not a routing one. Check the region string first whenever SES "mysteriously" rejects a send that worked yesterday.

SES limits are real and the transport does not shield you. 10 MB total message size including MIME encoding (so ~7 MB of raw attachment), a per-second send rate, and a 24-hour quota. If users can upload attachments, enforce a size cap above the transport, in a Mailable or a request rule. Also remember that base64 encoding inflates binary attachments by ~33% — a 9 MB PDF will fail at 10 MB after encoding.

SendRawEmail failures are opaque. The raw path returns a message ID but does not surface per-recipient rejection the way SendEmail does. If you need delivery diagnostics, subscribe to the SES event destinations (SNS → CloudWatch) — the package does not surface bounce/complaint data to the application.

Debugging checklist, in order:

  1. aws sesv2 get-account --region <region> to confirm sandbox status and quotas.
  2. aws sesv2 list-email-identities to confirm your sender is verified in the same region.
  3. Temporarily set MAIL_MAILER=log and confirm Laravel is invoking the mailable correctly — isolates mail code from transport.
  4. Add a var_dump($result->getMessageId()) or listener around the AsyncAws response — if MessageId is returned, SES accepted it and the problem is downstream (bounce, spam, suppressed).
  5. Check storage/logs for Aws\Exception\AwsException-shaped errors from AsyncAws; the class hierarchy differs from the full SDK but the AWS error codes (MessageRejected, Throttling) are identical.

Extension points are thin. The package exposes a transport, not a pluggable pipeline. If you need configuration sets, tags, or SES v2 features, you cannot get there through Laravel's mail config — you would subclass the transport (if it is final, you cannot) or fall back to Laravel's built-in ses driver with Mail::extend and the full AWS SDK. Decide this before writing custom code, not after.

Do not rely on the changelog to warn you. The 0.1.5 release note says "See change log" and the linked file is the only source of truth. Treat every patch as capable of breaking you, and add a note in your upgrade checklist that reading the diff matters more than reading the version number.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle