PHPackages                             touqeershafi/laravel-inbound-email - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. touqeershafi/laravel-inbound-email

ActiveLibrary

touqeershafi/laravel-inbound-email
==================================

Multi-provider inbound email webhooks for Laravel (Mailgun, Postmark, SendGrid, SES, Mailpit, Resend).

026↓75%PHPCI passing

Since Jul 15Pushed 1mo agoCompare

[ Source](https://github.com/touqeershafi/laravel-inbound-email)[ Packagist](https://packagist.org/packages/touqeershafi/laravel-inbound-email)[ RSS](/packages/touqeershafi-laravel-inbound-email/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

Laravel Inbound Email
=====================

[](#laravel-inbound-email)

Multi-provider inbound email webhooks for Laravel. Incoming HTTP requests are verified per provider, normalized into an `InboundMessage` DTO, and handled asynchronously via **one** queued job class you configure.

**Supported providers:** Mailgun, Postmark, SendGrid, Amazon SES (via SNS), Mailpit, Resend.

**Requirements:** PHP `^8.4`, Laravel `10.x`+ (Illuminate `^10`–`^13` per `composer.json`).

---

Install
-------

[](#install)

```
composer require touqeershafi/laravel-inbound-email
```

The package registers its service provider automatically (`extra.laravel.providers` in Composer).

### Publish configuration (recommended)

[](#publish-configuration-recommended)

```
php artisan vendor:publish --tag=inbound-email-config
```

This copies `config/inbound-email.php` into your app. Until you publish, the package merges the same defaults from the vendor file.

---

Routes
------

[](#routes)

Routes are registered under a configurable **prefix** (default `webhooks/inbound`). Middleware defaults to `api` (no session/CSRF). If you switch to `web`, add these paths to `VerifyCsrfToken` `$except` or use stateless verification.

### Single-tenant (default)

[](#single-tenant-default)

`organization_in_route` is `false`. Pattern:

```
POST {prefix}/{provider}
```

Examples (default prefix):

ProviderExample pathMailgun`POST /webhooks/inbound/mailgun`Postmark`POST /webhooks/inbound/postmark`SendGrid`POST /webhooks/inbound/sendgrid`SES (SNS)`POST /webhooks/inbound/ses`Mailpit`POST /webhooks/inbound/mailpit`Resend`POST /webhooks/inbound/resend`### Multi-tenant / SaaS

[](#multi-tenant--saas)

Set `INBOUND_EMAIL_ORG_IN_ROUTE=true` or `config(['inbound-email.organization_in_route' => true])`. Pattern:

```
POST {prefix}/{orgAlias}/{provider}
```

Example: `POST https://your-app.test/webhooks/inbound/acme-corp/mailgun`

- **`{orgAlias}`** — Your tenant slug (per organization). It must match the regex in `organization_alias_pattern` (default: slug-like ASCII; see `config/inbound-email.php`).
- The job receives **`$orgAlias` as a separate constructor argument** from the normalized message array (see [Processing messages](#processing-messages)).

**Switching modes:** With multi-tenant routes enabled, old single-segment URLs such as `POST /webhooks/inbound/mailgun` are **not** registered. Point each provider’s webhook at the per-organization URL instead.

**Prefix:** `INBOUND_EMAIL_ROUTE_PREFIX` or `config('inbound-email.route_prefix')` (no leading/trailing slashes required in env; the package trims as needed).

---

Configuration overview
----------------------

[](#configuration-overview)

Env / concernPurpose`INBOUND_EMAIL_ROUTE_PREFIX`URL prefix for all inbound routes (default `webhooks/inbound`).`INBOUND_EMAIL_ORG_IN_ROUTE``true` = `{orgAlias}/{provider}` URLs; `false` = `{provider}` only.`INBOUND_EMAIL_ORG_ALIAS_PATTERN`Regex (no delimiters) for `{orgAlias}` when org routing is on.`INBOUND_EMAIL_JOB`FQCN of your queued job (implements `ProcessesInboundEmail`). Default: package `DefaultProcessInboundEmailJob` (debug log only).`INBOUND_EMAIL_QUEUE_CONNECTION`Optional queue connection for the dispatch.`INBOUND_EMAIL_QUEUE`Optional queue name for the dispatch.Provider secrets and options (set only what you use):

EnvProvider`INBOUND_EMAIL_MAILGUN_SIGNING_KEY`Mailgun`INBOUND_EMAIL_POSTMARK_WEBHOOK_SECRET`Postmark`INBOUND_EMAIL_SENDGRID_VERIFICATION_KEY`SendGrid`INBOUND_EMAIL_SES_ALLOW_UNSIGNED_SNS`, `INBOUND_EMAIL_SES_S3_DISK`SES`INBOUND_EMAIL_MAILPIT_BASE_URL`, `INBOUND_EMAIL_MAILPIT_API_TOKEN`, `INBOUND_EMAIL_MAILPIT_WEBHOOK_SECRET`Mailpit`INBOUND_EMAIL_RESEND_WEBHOOK_SECRET`, `INBOUND_EMAIL_RESEND_API_KEY`, `INBOUND_EMAIL_RESEND_API_BASE_URL`ResendFull keys and comments live in the published `config/inbound-email.php`.

---

Processing messages
-------------------

[](#processing-messages)

The webhook controller verifies the request, builds an `InboundMessage`, and dispatches **your** job class from `config('inbound-email.job')`. There is no extra wrapper job.

### Job requirements

[](#job-requirements)

1. Implement `Touqeershafi\LaravelInboundEmail\Contracts\ProcessesInboundEmail` (extends `ShouldQueue`).
2. Use `Illuminate\Foundation\Bus\Dispatchable` (and typically `Queueable`, `InteractsWithQueue`, `SerializesModels`).
3. **`array $message`** — Serialized `InboundMessage` (`InboundMessage::toArray()` shape).
4. **Multi-tenant only:** second constructor parameter **`string $orgAlias`** — value of `{orgAlias}` from the URL. When `organization_in_route` is `false`, the package dispatches with **only** `$message`, so a one-argument constructor remains valid for single-tenant setups.

Rebuild the DTO in `handle()`:

```
$inbound = \Touqeershafi\LaravelInboundEmail\InboundMessage::fromArray($this->message);
```

### Dispatch behavior

[](#dispatch-behavior)

`organization_in_route`Call`false``YourJob::dispatch($messageArray)``true``YourJob::dispatch($messageArray, $orgAlias)`Queue connection and queue name from config are applied to the pending dispatch when set.

### Example job

[](#example-job)

```
use Illuminate\Bus\Queueable;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Touqeershafi\LaravelInboundEmail\Contracts\ProcessesInboundEmail;
use Touqeershafi\LaravelInboundEmail\InboundMessage;

final class HandleInboundEmail implements ProcessesInboundEmail
{
    use Dispatchable;
    use InteractsWithQueue;
    use Queueable;
    use SerializesModels;

    /**
     * @param  array  $message
     */
    public function __construct(
        public array $message,
        public string $orgAlias = '',
    ) {}

    public function handle(): void
    {
        $inbound = InboundMessage::fromArray($this->message);

        // When using organization_in_route, resolve the tenant from $this->orgAlias.
        // Use $inbound->provider, ->subject, ->text, ->metadata, etc.
    }
}
```

### Registering your job class

[](#registering-your-job-class)

**Environment or published config:**

```
INBOUND_EMAIL_JOB=App\Jobs\HandleInboundEmail
```

**Runtime (e.g. `AppServiceProvider`):**

```
$this->app->boot(function (): void {
    config(['inbound-email.job' => \App\Jobs\HandleInboundEmail::class]);
});
```

---

Development
-----------

[](#development)

```
composer test      # PHPUnit
composer analyse   # PHPStan
composer format    # Laravel Pint
```

###  Health Score

22

—

LowBetter than 21% of packages

Maintenance60

Regular maintenance activity

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/0ce7e2bbc4006ec5911490c8a0183938a72dfd2d720c50a2f8134ec9f046ab79?d=identicon)[touqeershafi](/maintainers/touqeershafi)

---

Top Contributors

[![touqeershafi](https://avatars.githubusercontent.com/u/4585116?v=4)](https://github.com/touqeershafi "touqeershafi (5 commits)")

### Embed Badge

![Health badge](/badges/touqeershafi-laravel-inbound-email/health.svg)

```
[![Health](https://phpackages.com/badges/touqeershafi-laravel-inbound-email/health.svg)](https://phpackages.com/packages/touqeershafi-laravel-inbound-email)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
