Postal integration for Laravel
Postal mail server integration for Laravel: a typed multi-server send transport, verified webhooks for delivery, bounce, open and click events, inbound email and an idempotent per-message status store.
Postal is a self-hosted mail server with an HTTP send API and signed webhooks. This package treats it as a typed delivery bus rather than a fire-and-forget mail driver: you send through a fully-typed client or transparently via MAIL_MAILER=postal, and you get the delivery outcome back as Laravel events instead of guessing.
What It Covers
Typed sending
Send via the mail transport or a typed client, with retries, typed exceptions and correct handling of Postal returning HTTP 200 with an error envelope.
Three connection types
Per server: api (structured JSON), smtp-api (raw RFC 2822 over the HTTP API) and smtp (classic submission).
Verified webhooks
RSA signatures checked over the raw request body, deliveries deduplicated on Postal's webhook uuid, and one typed Laravel event per Postal event type.
Delivery status store
An idempotent row per message with latest status, open and click counters and the owning model, plus a deduplicated event log.
Inbound email
Postal routes deliver to a signed endpoint that becomes a typed event with bodies, headers, attachments and raw source.
Multiple servers
One config entry per Postal mail server addressed by name, or provisioned dynamically from a database via a registry contract.
Diagnosis built in
A postal:doctor command checks servers, keys, routes, store tables, the mailer and live connectivity with CI-friendly exit codes, so a misconfigured key or an unregistered webhook route surfaces before your users find it. postal:ping, postal:tail and postal:message cover the day-to-day: is it reachable, what is arriving, and what happened to this one message.
Requirements
PHP 8.4+, Laravel 12 or 13. Tested against Postal 3.x. This site sends its own mail through it.