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

Ses Bundle Laravel Package

jplarar/ses-bundle

A Laravel bundle for sending email through Amazon SES, wrapping the AWS SDK in a service provider and configuration layer. It aims to simplify SES setup for Laravel apps, but with minimal documentation and low adoption, it suits small projects already committed to Amazon SES and willing to review th...

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing to internalize: this is a Symfony2 bundle, not a Laravel package. There is no service provider, no config/ses-bundle.php, and no facade. If you are working in a Laravel codebase you will not composer require this and have it "just work" — you'll either be working inside a legacy Symfony 2.x app that already depends on it, or you'll be reading its source to port the ~150 lines of SES wrapping into a Laravel service of your own.

Minimal steps inside a Symfony2 host app:

  1. composer require jplarar/ses-bundle (check the composer.json constraint against your PHP version first — the 2019 tag targets PHP 5.x/7.0-era Symfony).
  2. Register the bundle in app/AppKernel.php:
    new jplarar\SESBundle\SESBundle(),
    
  3. Configure credentials — typically under a jplarar_ses: key in app/config/config.yml, with AWS access key, secret, and region. Put the actual values in parameters.yml so they stay out of VCS:
    jplarar_ses:
        key:    "%aws_ses_key%"
        secret: "%aws_ses_secret%"
        region: "%aws_ses_region%"
    
  4. Confirm the service is wired by dumping the container: app/console container:debug | grep -i ses. Note the service id — the bundle exposes its API wrapper as a container service, and that id is what you'll inject everywhere.

Where to look first. Open the bundle's DependencyInjection/Configuration.php to see the actual accepted config keys (READMEs of low-star 2019 bundles drift from reality), then Resources/config/services.yml to see the service id and the class it instantiates. That class — the thin wrapper around the AWS SDK SES client — is the whole surface area you care about.

First use case. The most valuable day-one use is not "send mail" (Laravel's Mail + SES driver does that fine); it's sender/recipient verification management. In SES sandbox mode nothing sends until identities are verified, and this bundle gives you a programmatic verifyEmailAddress / listVerifiedEmailAddresses call from inside your admin tooling. Start there: build an artisan/console command that verifies a new noreply@ address and lists what's already verified, and you'll have exercised config, DI, and error handling in one go.

Implementation Patterns

Service injection over static calls. The bundle's value is that credentials are bound once at container build time. Inject the SES service into your mailer class constructor rather than reaching for the container:

class TransactionalMailer
{
    private $ses;

    public function __construct($ses) // whatever the bundle's service id resolves to
    {
        $this->ses = $ses;
    }

    public function send(Email $email)
    {
        return $this->ses->sendEmail([
            'Source'       => '[email protected]',
            'Destination'  => ['ToAddresses' => [$email->to()]],
            'Message'      => [
                'Subject' => ['Data' => $email->subject()],
                'Body'    => ['Html' => ['Data' => $email->html()]],
            ],
        ]);
    }
}

Verify-before-send as a guard. Wrap sends in a check that the Source identity is verified, cached for an hour. This turns the classic "MessageRejected: Email address is not verified" runtime failure into a build-time or boot-time failure, which is much cheaper to debug.

Raw MIME for anything non-trivial. The simple SendEmail API cannot do attachments, custom headers, or multipart bodies. For invoices, calendar invites, or List-Unsubscribe headers you need SendRawEmail — build the MIME with SwiftMailer/Symfony's mailer and hand the raw string to the bundle's raw-send method. Budget for this early; teams routinely discover the limitation after the "just add a PDF attachment" ticket lands.

Queue everything. SES calls are network-bound and throttleable. In Symfony, push the send onto a message queue and let a worker call the SES wrapper; in Laravel, the equivalent is a queued Mailable or a job wrapping your ported SES client. The pattern is identical either way and protects your request latency from SES Throttling responses.

Quota check before bulk. If you're sending campaigns or batched notifications, call getSendQuota first and chunk the batch to a fraction of your remaining 24-hour allowance. This is the single most useful method in the wrapper and it's easy to forget until a password-reset wave trips the limit and all transactional mail stops.

Porting to Laravel (the realistic path). Since this won't run natively: composer require aws/aws-sdk-php, add 'ses' => [...] config, bind an SesClient singleton in a service provider, and copy the wrapper's method shape (sendEmail, sendRawEmail, verify, listVerified, getSendQuota) into a SesMailer class. This is a couple of hours of work and buys you a maintained SDK instead of a 2019 bundle. Alternatively — and usually better — configure Laravel's built-in mailer with the ses transport and only hand-roll the verification/quota calls.

Environment parity. Because config lives in YAML parameters, keep key/secret/region per-environment so staging hits the SES sandbox and production hits the live service. Never let staging send to real customer addresses.

Gotchas and Tips

It is abandoned, and Symfony2 is EOL. Last release June 2019, one star, zero dependents. There will be no fixes for SDK breaking changes, PHP 8.x incompatibilities, or security advisories in the transitive AWS SDK. Treat it as frozen source you may need to vendor and patch, not a dependency you can rely on. If you're greenfielding, don't adopt this — use aws/aws-sdk-php directly.

Sandbox mode is the number-one time sink. A fresh SES account can only send to verified addresses. Symptom: MessageRejected with "not verified" even though credentials are clearly correct. Your verify/list admin command (above) is the antidote. Request production access separately.

Region matters and is not universal. SES is not available in every AWS region, and the region in your bundle config determines both the endpoint and, historically, the sending limits. Pick the region deliberately; a copy-pasted us-east-1 default silently works but may send from the wrong jurisdiction.

Credentials in config.yml is the default and it's wrong. Older docs show inline keys. Move them to parameters.yml or environment, and if you're porting, use an IAM role or instance profile instead of long-lived keys entirely.

Exceptions are raw SDK exceptions. The wrapper does not translate them. Catch Aws\Ses\Exception\SesException, and specifically distinguish Throttling / MessageRejected (retryable or fixable) from AccessDenied (misconfig). Log the SES messageId on success — it's the only handle you get for delivery troubleshooting, since SES bounce/complaint feedback arrives out-of-band via SNS, which this bundle does not touch at all.

No bounce/complaint handling. This is a genuine gap: SES will suspend your account for high bounce rates, and the bundle gives you nothing for SNS notifications, configuration sets, or suppression lists. Plan to build that yourself — an SNS topic on the SES identity pointing at an HTTP endpoint in your app that flips a bounced_at column — or you're flying blind.

Extension points are thin. The only realistic customization is (a) overriding the service definition to pass a pre-built Aws\Ses\SesClient you configured yourself, or (b) decorating the wrapper class. Prefer (a): it lets you inject a client with custom retry/backoff middleware without forking the bundle.

Debugging checklist. Before blaming the bundle, verify in order: service registered (container:debug), config key names match Configuration.php, credentials load (var_dump the resolved parameters in a console command), region string valid, identity verified, and you're out of the sandbox. Ninety percent of "it doesn't work" reports land on one of the last three.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin