jprangenbergde/temporary-email-detection
Detect disposable and temporary email addresses in Laravel with jprangenbergde/temporary-email-detection. A lightweight package for validating signups and blocking throwaway inboxes from known providers, helping keep your user base and mailing lists clean.
This release (v1.2) is small but structural: it introduces ClientInterface and ClientFactoryInterface. Those two types are the first thing to look at, because they define the seams the rest of the package is built around — everything else (HTTP transport, auth, retries, config) sits behind them.
Start here, in this order:
ClientInterface is an implementation detail you should not depend on.ClientFactoryInterface and ClientInterface to concrete classes. That binding is where Laravel wiring happens and where you would override behaviour.php artisan vendor:publish). Credentials, base URLs, timeouts and retry counts almost always live there rather than in the interfaces.make()/create() method. It decides whether you get a shared client or a fresh one per call — that distinction matters later.A sensible first use case: take one existing controller or job that talks to the external service directly, and refactor it to type-hint ClientInterface in the constructor. If the app boots and the call still works, your bindings are correct and you have a template for the rest of the codebase.
final class SyncOrders
{
public function __construct(private ClientInterface $client) {}
public function handle(): void
{
$this->client->send(/* ... */);
}
}
Do not resolve the factory inside business logic unless you genuinely need a different client per call (multi-tenant, per-user credentials, multiple endpoints). For the common case, inject the client.
Inject the interface, never the concrete class. This is the whole point of the release. Constructor injection of ClientInterface gives you testability and lets the package swap implementations without touching your code.
Use the factory for context-dependent clients. When credentials or base URLs vary per tenant or per integration, inject ClientFactoryInterface and call it at the point of use. Keep the factory call in a small dedicated class (a "client resolver") rather than scattering it through controllers.
Overriding the binding. If you need custom behaviour — logging, header injection, a different transport — bind your own implementation in a service provider:
$this->app->bind(ClientFactoryInterface::class, TenantAwareClientFactory::class);
Prefer decorating the package's implementation over reimplementing the interface from scratch; you keep upstream fixes.
Testing. Because both types are interfaces, tests become straightforward:
$this->mock(ClientInterface::class, function ($mock) {
$mock->shouldReceive('send')->once()->andReturn($response);
});
For factory-driven code, mock ClientFactoryInterface to return your fake client. This is far cleaner than hitting the network or stubbing HTTP clients, and it's the main day-to-day payoff of v1.2.
Singletons vs. fresh instances. If the provider registers the client as a singleton, state (headers, auth tokens) persists across the request — convenient, but a footgun in long-running queue workers where tokens expire. If the factory produces a new instance each time, you pay construction cost per call. Check the provider and choose deliberately; consider scoped bindings for Octane and queue contexts.
ClientInterface yourself, you own that risk — decorate instead where possible.register() order in bootstrap/providers.php / config/app.php). Overriding in register() of your own provider usually works; overriding in boot() often does not.php artisan config:clear. A stale cached config is the single most common cause of "my new credentials aren't being picked up".ClientInterface (or vice versa). Confirm which type is actually type-hinted before writing the mock.Target [ClientInterface] is not instantiable means the package provider isn't registered or is deferred and never triggered. Check bootstrap/providers.php and whether the package uses deferred providers.ClientInterface, not a fork.How can I help you explore Laravel packages today?