Add Resend inbound email driver - #144
Open
jasonfish568 wants to merge 14 commits into
Open
Conversation
jasonfish568
marked this pull request as ready for review
July 29, 2026 07:24
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This adds a Resend inbound driver to Laravel Mailbox.
Resend differs from the existing inbound providers: its
email.receivedwebhookcontains metadata and an
email_id, but not the raw email. The driver musttherefore verify the webhook, retrieve the receiving record from Resend, and
download the raw MIME message before it can reuse Laravel Mailbox's existing
InboundEmail::fromMessage()pipeline.The processing flow is:
data.email_idProcessResendEmailjob on the configured queue connectiondownload URL
Why queue processing is included
Processing a Resend webhook requires two outbound HTTP operations—the Receiving
API lookup and the raw MIME download—followed by MIME parsing. Messages may also
contain large attachments. Doing all of that inside the webhook request can
make response time depend on Resend, the download host, and message size.
The queue integration provides:
syncdefault, so existing and low-volume applications need no workerwebhook to return HTTP 200 after the job has been accepted
processing failures
messages
Webhook and queue delivery remain at-least-once. The driver intentionally does
not add a long-lived unique-job lock; mailbox handlers with side effects should
use a stable business key such as the raw email's
Message-Idfor idempotency.Why the HTTP, Guzzle, Bus, Queue, and Cache dependencies are declared
These are runtime dependencies used directly by the driver, rather than
unrelated framework additions:
illuminate/httpguzzlehttp/guzzleilluminate/busQueueablesupportilluminate/queueShouldQueue, queue connection selection, retries, backoff, middleware, and worker integrationilluminate/cacheRateLimiter, used to keep concurrent workers within Resend's per-team API allowanceFull Laravel applications normally already contain these framework components
and Guzzle. Declaring them explicitly prevents the package from relying on
undeclared transitive dependencies when it is installed with individual
Illuminate components.
The driver uses Laravel's existing HTTP client instead of adding the Resend PHP
SDK. Webhook verification is implemented with the documented Svix HMAC format,
PHP's built-in hashing functions, constant-time comparison, and timestamp
validation. This keeps the dependency surface focused on components already
used by Laravel applications.
Rate limiting and high-volume operation
Resend's default API allowance is five requests per second per team. Multiple
queue workers could otherwise exceed that limit even when each worker is
healthy.
MAILBOX_RESEND_RATE_LIMITtherefore defaults to5, and the job usesLaravel's cache-backed rate limiter before calling the Receiving API.
Applications running workers on multiple nodes should use a shared cache store
with atomic increments, such as Redis. The limiter is only for the external API
rate; it is not used as a webhook deduplication lock.
What changed
resendmailbox driver and webhook route using the repository'sexisting invokable-controller style
svix-id,svix-timestamp, andsvix-signatureagainst the raw bodyforwarding the API key to the download URL
processing for higher volume
limit
MIME, attachment, retry, duplicate-delivery, and rate-limit coverage
Validation
composer testsets (102 tests and 218 assertions in each environment)
Cloudflare tunnel and Resend Receiving
retrieval, raw MIME parsing, text and HTML bodies, attachment integrity, and
inbound email persistence