Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Postmaster Laravel Package

stechstudio/laravel-postmaster

Laravel Postmaster gives your Laravel app a clean, centralized way to compose and send transactional email, with a fluent API that keeps mail logic out of controllers and supports queued delivery.

View on GitHub
Deep Wiki
Context7

Getting Started

laravel-postmaster sits between your app and a transactional email provider's HTTP API, so day-to-day you keep writing normal Laravel mail (Mail::to(...)->send(...)) and only touch the package when configuring transports or consuming delivery events.

Minimal path from zero:

  1. composer require stechstudio/laravel-postmaster
  2. Publish the config: php artisan vendor:publish --tag=postmaster-config (also check for a migrations tag if you plan to persist delivery events).
  3. Add credentials to .env — one block per provider, e.g. POSTSHIBA_KEY=... — and keep secrets out of config/*.php.
  4. Point a mailer at the driver in config/mail.php:
'mailers' => [
    'postshiba' => [
        'transport' => 'postshiba',
    ],
],
  1. Set MAIL_MAILER=postshiba for the environment you're testing and send a real message through a queued mailable.

Where to look first: the published config/postmaster.php (the authoritative list of supported providers and their credential keys), then the driver classes under src/ — each provider gets its own class, so the PostShiba driver's options are the best documentation for what that provider actually supports. After that, the webhook/event handling entry point (route registration + event classes), which is where most of the package's real value lives.

First use case worth shipping: replace an SMTP mailer with the API driver in staging, confirm deliverability and headers, then wire bounce/complaint events into your existing suppression logic before you flip production.

Implementation Patterns

Keep application code provider-agnostic. Everything downstream of Mail:: should be unaware of PostShiba. Configure the driver per environment and let the mailer name be the only switch. This is what makes adding v2.32.0's provider a config change rather than a refactor.

Regional or failover routing via multiple mailers. The practical reason to add another provider is usually geography, cost, or redundancy. Define two mailers (postshiba, postmark) and select at runtime:

Mail::mailer($user->isInJapan() ? 'postshiba' : 'postmark')
    ->to($user)
    ->send(new Receipt($order));

Better still, wrap that decision in a small MailRouter service or a Mailable-level ->mailer() call so tests can assert on the choice rather than the transport.

Always queue. API transports turn a send into an outbound HTTP round-trip; a slow provider becomes slow page loads. implements ShouldQueue on mailables (or Mail::queue) plus a dedicated queue worker keeps request latency flat and gives you retries via failed() / retryUntil().

Consume provider events, don't poll. The highest-leverage integration is the webhook side: register the package's route, verify signatures, and translate provider events into domain state (mark address invalid on hard bounce, unsubscribe on complaint). Map provider-specific event names in one place so a second provider's payload shape doesn't leak into your models.

Test at the seam. For most feature tests, Mail::fake() is still correct and fast — it asserts intent without exercising the transport. Reserve real provider calls for a thin integration test suite against a sandbox key, and keep them out of CI's default run so a provider outage doesn't fail unrelated PRs.

Extension point. If you need behavior the bundled driver doesn't expose (custom headers, provider-specific tags), don't fork the package — register a subclass and rebind the transport in a service provider. Keep customizations in your own namespace so upstream releases merge cleanly.

Gotchas and Tips

  • v2.32.0 is additive only. A single new driver (PostShiba) with no changes to existing providers, config keys, or public APIs. Upgrading is safe; you only need to re-publish/merge config if the provider list is enumerated there rather than derived.
  • Re-run php artisan config:cache after adding credentials. Config caching is the most common cause of "the driver isn't found" or "credentials are null" in staging while php artisan tinker works fine locally.
  • Driver-name string must match exactly. 'transport' => 'postshiba' (not PostShiba, not post-shiba). A mismatch surfaces as a InvalidArgumentException: Unsupported mail transport from Laravel's transport manager, not from this package — check config/mail.php before filing an issue.
  • Feature parity is not guaranteed across providers. The new driver may not support tags, metadata, scheduled send, or attachment handling the way your current one does. Before routing traffic to it, send a message with an attachment, a non-ASCII body, and a custom header, and confirm each lands. Don't assume a provider swap is behavior-neutral.
  • Webhook signature verification needs the provider's signing secret, which is often a different credential from the API key. Missing it fails silently as a 403 with no useful log line. Log the raw payload hash on verification failure while bringing a new provider online.
  • Idempotency. Providers retry webhooks. Wrap your event handlers in ShouldBeUnique jobs or a dedupe key on (provider, event_id), or you'll double-count bounces and double-unsubscribe.
  • Rate limits are per-provider and often per-second. Bulk sends through a newly added provider will hit 429s that the package may surface as generic transport exceptions. Add jitter/backoff on the queue, or use RateLimited job middleware.
  • Debugging sends: log the provider's response body at debug level in a dedicated channel. Once mail leaves the API, "it didn't arrive" is undebuggable without the provider's message ID — store it on your outbound email record so support requests and webhook events can be joined.
  • Pin the version in composer.json (^2.32) and read the changelog between minor bumps; this package's changelog is provider-driven and each addition is a new surface area for config drift.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle