stampie/extra
stampie/extra extends Stampie, the PHP library for sending email through provider APIs, with additional adapters, helpers, and convenience classes. It simplifies adding extra mail-service integrations and common email-sending functionality to PHP applications.
stampie/extra is a small set of decorator mailers around stampie/stampie. It does not replace the base library; it gives you ready-made wrappers for logging, profiling, retrying, rate-limiting, tagging, and identity/from-address switching without touching your existing send calls.
Minimal setup:
composer require stampie/extra
You still need a base Stampie mailer and HTTP adapter. Then wrap it:
use Stampie\Mailer\Mailgun;
use Stampie\Extra\Retry\Mailer as RetryMailer;
use Stampie\Extra\Logger\Mailer as LoggerMailer;
$base = new Mailgun($adapter, $apiKey, $domain);
$mailer = new RetryMailer($base, 3); // retry transient failures
$mailer = new LoggerMailer($mailer, $psr3Logger); // log every attempt
$mailer->send($message);
Look first at vendor/stampie/extra/src. The useful classes are the decorators: Logger\Mailer, Profiler\Mailer, Retry\Mailer, RateLimit\Mailer, Tagger\Mailer, and Identity\Mailer. They all implement Stampie\MailerInterface, so they are drop-in replacements for the base mailer.
The first realistic use case: you already send transactional mail through Stampie and want retry, logging, and rate limiting without changing every call site. Swap the mailer in one place, e.g. a Laravel service provider binding.
Note: the package was archived in May 2022. Pin a specific version, run
composer audit, and expect to fork or vendor it if you need PHP 8.2+ compatibility fixes.
Build an onion, outermost first. Decorator order is meaningful:
$mailer = new Mailgun($adapter, $key, $domain); // transport
$mailer = new RateLimitMailer($mailer, $limiter); // protect provider quota
$mailer = new RetryMailer($mailer, 3); // retry what gets through
$mailer = new LoggerMailer($mailer, $logger); // observe all attempts
$mailer = new ProfilerMailer($mailer); // dev only
A retry inside a rate limiter can burn quota on repeated failures; a logger outside a retry sees every attempt, which is usually what you want for debugging.
Bind it once in Laravel. Do not construct decorators per request or per job:
$this->app->singleton(\Stampie\MailerInterface::class, function ($app) {
$base = new \Stampie\Mailer\SendGrid($adapter, config('services.sendgrid.key'));
$mailer = new \Stampie\Extra\Retry\Mailer($base, 3);
$mailer = new \Stampie\Extra\Logger\Mailer($mailer, $app['log']->channel('mail'));
return $mailer;
});
Resolve Stampie\MailerInterface in jobs and services.
Use Identity\Mailer for multi-tenant or multi-brand apps. Instead of scattering setFrom() calls, wrap the mailer with an identity object so all mail for a tenant uses consistent from/reply-to addresses. This keeps sending logic out of your message factories.
Use Tagger\Mailer for provider analytics. If your provider supports tags/categories (SendGrid, Mailgun, etc.), tagging at the mailer layer avoids adding provider headers in every message. Tags that a provider does not support are usually ignored — verify per transport.
Queue sends in Laravel, but avoid double retries. If you use Laravel queues and Retry\Mailer, decide which layer owns retries. A common pattern is: queue job handles re-queuing for application-level failures; Retry\Mailer handles short transient network/5xx blips inside a single attempt.
Testing. Implement a tiny Stampie\MailerInterface that records sent messages, and compose your decorators around it. Assert on captured messages rather than hitting a provider. Keep a config flag that swaps in this fake for local/test environments.
Message construction. Stampie messages expose from/to/subject/text/html/headers/attachments via Stampie\Message or your own MessageInterface implementation. Build a small factory or mapper so decorators only deal with MailerInterface, not message assembly.
stampie/extra as frozen: pin the version, test on your PHP version, and be prepared to copy the decorators into your app if you need changes.sendBatch support varies. If you rely on batch sending, confirm each decorator forwards sendBatch; a decorator that only implements send() will silently disable batching.$this->release() or failed() appropriately rather than letting every exception bubble.Stampie\MailerInterface can sit in the chain. Writing your own decorator (metrics, tenant context, suppression list) is usually easier than modifying stampie/extra — and it survives the archived status.How can I help you explore Laravel packages today?