pushery / ses-inbound-mail-for-laravel
Receive mail through Amazon SES in Laravel: a verified SNS endpoint, takeover from the S3 transit, reconciliation, a check for stuck mail and AWS setup.
Package info
github.com/pushery/ses-inbound-mail-for-laravel
pkg:composer/pushery/ses-inbound-mail-for-laravel
Requires
- php: ^8.4
- ext-json: *
- ext-mbstring: *
- aws/aws-php-sns-message-validator: ^1.10
- aws/aws-sdk-php: ^3.395
- illuminate/bus: ^13.0
- illuminate/config: ^13.0
- illuminate/console: ^13.0
- illuminate/container: ^13.0
- illuminate/contracts: ^13.0
- illuminate/database: ^13.0
- illuminate/filesystem: ^13.0
- illuminate/http: ^13.0
- illuminate/log: ^13.0
- illuminate/routing: ^13.0
- illuminate/support: ^13.0
Requires (Dev)
- fakerphp/faker: ^1.24
- larastan/larastan: ^3.9.3
- laravel/ai: ^1.0
- laravel/boost: ^2.9
- laravel/mcp: ^1.0
- laravel/pao: ^1.1
- laravel/pint: ^1.0
- orchestra/testbench: ^11.2
- pestphp/pest: ^5.2.1
- pestphp/pest-plugin-agent: ^5.0
- pestphp/pest-plugin-browser: ^5.2
- pestphp/pest-plugin-evals: ^5.1
- pestphp/pest-plugin-laravel: ^5.0
- pestphp/pest-plugin-phpstan: ^5.0
- pestphp/pest-plugin-type-coverage: ^5.0
- phpstan/phpstan: ^2.3.0
- pushery/sqlens-for-laravel: ^0.33
- rector/rector: ^2.7.0
- spatie/laravel-health: ^1.40
- spaze/phpstan-disallowed-calls: ^4.12
- symfony/yaml: ^7.4.17 || ^8.1.5
Suggests
- spatie/laravel-health: For the check that fails while a mail waits in transit past its time (Pushery\SesInboundMail\Health\NoMailIsStuckInTransitCheck).
Provides
None
Conflicts
None
Replaces
None
README
SES Inbound Mail for Laravel
Receive mail through Amazon SES in Laravel: a verified SNS endpoint, takeover from the S3 transit, reconciliation, a check for stuck mail and AWS setup.
Documentation
Full documentation at docs.pushery.com/ses-inbound-mail-for-laravel. This README is the quick start; the guides and the configuration reference live there.
Requirements
- PHP 8.4+
- Laravel 13+
Tested on PostgreSQL and MySQL 8.4, the databases Laravel Cloud runs (serverless Postgres and MySQL 8.4 LTS), so it runs there out of the box. The fast suite runs on SQLite.
Tested on PHP 8.4 — the floor of the declared range, because a >= promise is
only proven by running on the boundary — and on PHP 8.5, so the upper half of
^8.4 is exercised here rather than first by a consumer.
Installation
composer require pushery/ses-inbound-mail-for-laravel
The service provider is registered automatically through package discovery.
Configuration
Publish the configuration file:
php artisan vendor:publish --tag=ses-inbound-mail-config
This writes config/ses-inbound-mail.php, where every option is documented inline.
The package records every mail it receives in a table of its own, ses_inbound_mails, and
php artisan migrate runs its migration from the package as it is. To keep the migration in your
application instead, call
\Pushery\SesInboundMail\SesInboundMailServiceProvider::ignoreMigrations() in the register method of your
AppServiceProvider first, then publish and run it:
php artisan vendor:publish --tag=ses-inbound-mail-migrations php artisan migrate
Without that call both copies stay registered, and with Laravel's default configuration the
published one runs under a new name and fails on a table that already exists. The same goes
for --tag=ses-inbound-mail, which publishes every resource at once, the migrations included.
Usage
Bind what your application does with a received mail:
use Pushery\SesInboundMail\Contracts\ReceivesInboundMail; use Pushery\SesInboundMail\ReceivedMail; final class OpenAConversation implements ReceivesInboundMail { public function receive(ReceivedMail $mail): void { // The original lies on $mail->disk under $mail->path, with $mail->sha256. } } $this->app->bind(ReceivesInboundMail::class, OpenAConversation::class);
Name the topics of Amazon SNS the endpoint takes, and set up the receiving path in AWS:
SES_INBOUND_MAIL_TOPICS=arn:aws:sns:eu-central-1:123456789012:inbound-mail php artisan ses-inbound-mail:setup-aws
SNS delivers to POST /ses-inbound-mail/notifications, every message is checked against its
signature, and every mail is taken over once, byte for byte, before your application receives it.
A reconciliation every five minutes takes what no notification reported.
The documentation describes every step and setting.
Testing
The test suite is not part of the published package: the tests and their PHPUnit
configuration stay in the development repository, so a clone of this repository has no
composer test. CONTRIBUTING.md says how a change is tested on its way in.
Security
Please review the security policy and report vulnerabilities privately rather than opening a public issue.
Built by Pushery
This package is built and maintained by Pushery — a Berlin-based studio building Laravel applications, SaaS products, and open-source tools.
Building a Laravel UI? WireKit is Pushery's open-source Livewire component kit. Browse the rest of our work at pushery.com.
License
The MIT License (MIT). See LICENSE for details.