akhan619/laravel-ses-event-manager
Laravel package for receiving and managing Amazon SES event notifications via SNS. It stores delivery, bounce, complaint, and other events, and helps maintain email suppression lists so your app can react to deliverability issues automatically.
The package's job is to accept AWS SES/SNS notification payloads, verify them, and turn them into something your Laravel app can act on. The fastest path in:
composer require <vendor>/<package>, then php artisan vendor:publish --tag=<package>-config.Bounce and Complaint notifications and mark the address undeliverable/suppressed in your own email_suppressions table.v1.0.4 is relevant here: AWS now populates notificationType where older payloads used eventType. Confirm which one your config/mapping keys against before you wire up any string comparisons — see Gotchas below.
Queue the endpoint. The webhook route should do the minimum: verify, persist the raw payload, dispatch a job, return 200 immediately. SNS retries aggressively on non-2xx, so slow handlers turn into duplicate storms.
Normalise once at the boundary. Convert the incoming notification into your own domain event (EmailBounced, EmailComplained, EmailDelivered) as early as possible. Everything downstream — listeners, jobs, notifications — should depend on your event, not on the AWS payload shape. This is what insulates you from the eventType → notificationType transition.
Idempotency key. Store the SNS MessageId with a unique index. Retries and overlapping deliveries are normal; without this, complaint handling double-fires and suppression logic gets noisy.
Testing. Build fixtures from real payloads and keep two: one using eventType, one using notificationType. Run both through your mapping in feature tests, so a future AWS field change fails a test rather than silently producing an unhandled notification type.
Local development. Add a APP_ENV=local bypass for signature verification (if the package offers one) and replay stored payloads via a test route or Http::fake(). Don't disable verification anywhere but local.
eventType vs notificationType. v1.0.4 adds handling for AWS's notificationType field. If you have existing match/switch statements or if checks against eventType on the raw payload, audit them — depending on how the package normalises, the raw field may no longer be populated for SES event-publishing notifications. Prefer the package's parsed event/type over the raw key.Message is a JSON string. The outer body is the notification; the inner Message is the SES event. Accessing the wrong level is the most common bug.$request->all() or re-encoding the JSON breaks the canonical string and you'll get spurious signature failures. Use $request->getContent().text/plain; charset=UTF-8. Some strict middleware/CSRF setups choke on this; make sure the webhook route is outside web middleware or the CSRF exemption is applied.SubscriptionConfirmation requires a GET to SubscribeURL; ignoring it means the subscription silently never becomes active. It is not a bounce or a delivery.Permanent vs Transient vs Undetermined — only suppress on permanent. Complaints should always suppress.How can I help you explore Laravel packages today?