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

Plunk Laravel Laravel Package

sohaibilyas/plunk-laravel

A Laravel integration for Plunk, the open-source email platform, making it easy to send transactional and marketing email through Plunk's API from your application. Includes a simple mail transport, configuration, and Laravel-friendly helpers for quick setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal path from install to first send:

  1. composer require <vendor>/<package> — pin to ^3.0.2 if you use standard Laravel password reset notifications (see Gotchas).
  2. Publish the config: php artisan vendor:publish --tag=<package>-config and set the API key/endpoint in .env.
  3. Do not hand-wire a service provider or transport. The package auto-registers its mailer on boot; the mailer appears in config/mail.php under mailers without any edit on your side.
  4. Point mail at it — either globally with MAIL_MAILER=<package> in .env, or per-send:
Mail::mailer('<package>')->to($user)->send(new WelcomeMail($user));

Where to look first: the published config file (endpoint, key, timeout, debug/serialized-request logging), then the Mail facade's mailer() calls already in your app to decide global vs. per-send selection.

First use case: a queued transactional mailable with one or two custom headers. It exercises the whole surface — transport selection, header serialization, and queue behavior — in a few lines.

Implementation Patterns

Per-notification mailer selection. Keep the default SMTP mailer for internal mail and opt into the package only for customer-facing transactional sends:

public function via($notifiable): array
{
    return [Channels\MailChannel::class];
}

public function toMail($notifiable): Mailable
{
    return (new OrderShipped($this->order))
        ->mailer('<package>');
}

Custom headers. Set them on the mailable (via Symfony message headers or the package's header API, depending on your version) and treat the value as a flat string map:

$mailable->withSymfonyMessage(function (Email $message) {
    $message->getHeaders()->addTextHeader('X-Order-Id', (string) $this->order->id);
});

Only add a header when you actually have a value — don't pass [], null, or an empty collection through.

Queued sends. Because queue retry idempotency is handled by the package, failed jobs can be retried (php artisan queue:retry) without producing duplicate deliveries. Let the package own the retry semantics; don't wrap sends in your own dedupe layer.

Standard Laravel flows stay untouched. Password resets, email verification, and other framework notifications use the default MailMessage path with no custom headers. On ^3.0.2 these serialize correctly. If you have a custom ResetPassword notification that subclasses the framework one, verify it still sends after upgrading.

Testing. Use Mail::fake() for assertions in feature tests, and reserve real-HTTP tests for a small suite that hits a sandbox endpoint with serialized-request logging enabled — that's where header-shape regressions actually surface.

Gotchas and Tips

Upgrade to 3.0.2 before shipping password resets. Prior versions serialized an absent custom-header set as a JSON array ([]) instead of omitting it, producing an invalid API payload. The symptom is a rejected/422 request for mail you never customized — most visibly the stock Laravel password reset notification. Populated headers were always sent as objects; only the empty case was broken. Pin ^3.0.2 and add one regression test that sends a header-less notification.

Don't confuse empty with absent. The fix is "omit when empty," not "send {}." If you build headers dynamically, filter the map before handing it over; a header with an empty-string value is still a header and may be rejected by the API.

Don't double-register the mailer. Auto-registration happens on boot. Adding your own Mail::extend or a mailers entry for the same name causes confusing precedence bugs where config changes appear to be ignored.

Retry semantics depend on package-internal state. Idempotency is unchanged in this release, so retries are safe — but if you clone or re-dispatch a mailable manually, you're outside that guarantee. Prefer queue:retry over re-sending.

Debugging serialization. Turn on the serialized-request logging in the config (never in production) to see exactly what's posted. That log is the fastest way to tell a header-shape problem from an auth or endpoint problem.

Extension points. Custom header classes and a swapped transport binding are the two supported layers; keep business logic out of both. Compatibility is validated on Laravel 12 and 13 — if you're on an older major, treat this release as untested and check the CI matrix before upgrading.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource