Postal integration for Laravel
Events
Events
One event class exists per Postal webhook event type; all implement
Cbox\LaravelPostal\Events\PostalWebhookEvent and expose server(),
type(), uuid() (Postal's webhook request uuid — the idempotency key) and
occurredAt().
| Event class | Postal event | Payload DTO |
|---|---|---|
PostalMessageSent |
MessageSent |
MessageStatusPayload |
PostalMessageDelayed |
MessageDelayed |
MessageStatusPayload |
PostalMessageDeliveryFailed |
MessageDeliveryFailed |
MessageStatusPayload |
PostalMessageHeld |
MessageHeld |
MessageStatusPayload |
PostalMessageBounced |
MessageBounced |
MessageBouncedPayload |
PostalMessageLinkClicked |
MessageLinkClicked |
MessageLinkClickedPayload |
PostalMessageLoaded (= opened) |
MessageLoaded |
MessageLoadedPayload |
PostalDomainDnsError |
DomainDNSError |
DomainDnsErrorPayload |
PostalSendLimitApproaching |
SendLimitApproaching |
SendLimitPayload |
PostalSendLimitExceeded |
SendLimitExceeded |
SendLimitPayload |
PostalInboundMessage |
— (route → HTTP endpoint, not a webhook) | InboundMessage |
Payload shapes were verified against Postal 3.3.7's source, not guessed from docs:
MessageStatusPayload—message(WebhookMessage),status(Sent/SoftFail/HardFail/Heldas Postal reports it),details,output(SMTP transcript excerpt),sentWithSsl,timestamp,time.MessageBouncedPayload—originalMessageandbounce, bothWebhookMessage(the bounce is its own inbound message).MessageLinkClickedPayload—message,url,token,ipAddress,userAgent.MessageLoadedPayload—message,ipAddress,userAgent.DomainDnsErrorPayload—server(ServerInfo),domain,uuid,dnsCheckedAt, and per-recordspf/dkim/mx/returnPathstatus + error.SendLimitPayload—server(ServerInfo),volume,limit.
WebhookMessage carries id (Postal's internal id), token, direction,
messageId (RFC id), to, from, subject, timestamp, spamStatus,
tag.
Listening
use Cbox\LaravelPostal\Events\PostalMessageDeliveryFailed;
Event::listen(function (PostalMessageDeliveryFailed $event) {
// typed all the way down
$event->payload->message->to;
$event->payload->output;
});
Events are dispatched by the queued webhook job, so listeners run on your queue workers. Unknown event types from future Postal versions are ignored (deny-by-default) — nothing is stored and no event fires.