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 Mailcheck Laravel Package

romanzipp/laravel-mailcheck

romanzipp/laravel-mailcheck integrates Mailcheck.ai with Laravel to detect disposable, temporary, and throwaway email addresses. It provides a simple validation rule so you can reject risky signups before they reach your database.

View on GitHub
Deep Wiki
Context7

Getting Started

Install with Composer and let Laravel's package discovery wire up the service provider:

composer require romanzipp/laravel-mailcheck

Publish the config so you can point the wrapper at the MailCheck.ai API and set an optional API key:

php artisan vendor:publish --tag=mailcheck

This drops a config/mailcheck.php file. Populate the relevant env vars in .env (e.g. MAILCHECK_API_KEY) and confirm the base URL is https://api.mailcheck.ai unless you're proxying requests.

First use case — reject disposable addresses during registration. The package registers a disposable validation rule, so the fastest win is:

$request->validate([
    'email' => ['required', 'string', 'email', 'disposable'],
]);

Look first at:

  1. config/mailcheck.php — API key, base URL, and any timeout/cache options exposed by the wrapper.
  2. The package's MailCheck service class (resolved from the container, usually also facadable) — this is where isDisposable() / isDomainDisposable() live.
  3. vendor/romanzipp/laravel-mailcheck/src for the rule class if you need custom messages or to extend behaviour.

Implementation Patterns

Inline validation on a FormRequest. The idiomatic Laravel usage is to add the rule to your existing email validation rather than creating a separate validator:

public function rules(): array
{
    return [
        'email' => ['required', 'email', 'max:255', 'disposable'],
    ];
}

public function messages(): array
{
    return [
        'email.disposable' => 'Please use a permanent email address.',
    ];
}

Domain-only checks. If you're validating a company website or a signup domain rather than a full email, call the service directly:

use RomanZipp\MailCheck\MailCheck;

public function store(MailCheck $mailCheck)
{
    if ($mailCheck->isDomainDisposable($request->input('domain'))) {
        return back()->withErrors(['domain' => 'Disposable domains are not allowed.']);
    }
}

Wrap it in a dedicated service. For larger apps, hide the package behind your own DisposableEmailChecker interface so tests and future providers don't reach into the vendor namespace:

class DisposableEmailChecker
{
    public function __construct(private MailCheck $mailCheck) {}

    public function check(string $email): bool
    {
        return Cache::remember("disposable:{$email}", now()->addDay(), fn () => $this->mailCheck->isDisposable($email));
    }
}

Bind the interface in a service provider and inject it wherever needed. This is also the seam you use to swap the implementation in tests.

Combine with complementary rules. Disposable is one signal. Pair it with email:rfc,dns (Laravel 10+) or your own MX lookup, and optionally a role-account check (admin@, info@) — but keep them as separate rules so error messages stay actionable.

Async / queued checks for high-volume flows. If you're screening large imports, queue the API call rather than blocking a request. The API call is per-email, so batch through a job and store results on the user/lead record.

Testing. Since the wrapper is just HTTP under the hood, use Http::fake() in your test suite:

Http::fake([
    'api.mailcheck.ai/*' => Http::response(['disposable' => true], 200),
]);

$this->post('/register', ['email' => '[email protected]'])
     ->assertSessionHasErrors('email');

For anything you control, prefer binding a fake DisposableEmailChecker in the container so tests don't depend on the vendor's response shape.

Gotchas and Tips

  • Every validation is a network round-trip. The disposable rule calls the MailCheck.ai API synchronously. On a hot registration endpoint this adds latency and couples your signup flow to a third-party service. Cache results (per email or per domain) and consider a short TTL — the disposable-domain list changes slowly.
  • Fail-open vs fail-closed. Decide what happens when the API is down or times out. Silently passing validation (fail-open) is usually the right trade-off for signup; failing closed will block legitimate users during outages. Check how the package handles non-200 responses and wrap calls in try/catch where it throws.
  • Add a timeout and retry policy. Configure a short HTTP timeout (2–3s) so a slow API doesn't hang your request. If the package doesn't expose this, publish the config and look for a timeout key, or bind a custom Guzzle client.
  • disposable is not a substitute for email. Always keep the base email rule first. The package assumes a well-formed address; garbage input may yield surprising API responses.
  • Rate limits and API keys. MailCheck.ai throttles unauthenticated and free-tier traffic. If you see 429s in logs, set MAILCHECK_API_KEY and back off via a queued job rather than retrying inline.
  • Config cache after publishing. If you add env vars, remember php artisan config:clear in development — a stale cached config with an empty API URL is a common silent failure.
  • Debugging. php artisan tinker and calling app(MailCheck::class)->isDisposable('[email protected]') is the quickest way to isolate whether a failure is in your rule setup or the API call. Log the raw response when status is unexpected.
  • Extension points. If you need to change behaviour (caching layer, alternate provider, custom messages), bind your own implementation of the underlying service or the rule in a service provider. Avoid editing vendor files — patches will be lost on the next composer update.
  • Coverage is per-domain, not per-mailbox. [email protected] and [email protected] return the same verdict. If you need finer-grained blocking (specific aliases, catch-all detection), that's your own layer on top.
  • Don't over-block. Some legitimate services (privacy-focused email providers, forwarded addresses) may be flagged. Give users a clear error message and, for B2B products, a support path to appeal.
  • Version pinning. With only 5 stars and 0 known dependents, treat this as a thin wrapper: pin the version in composer.json and skim the source before upgrading. If you need long-term stability, consider calling the MailCheck.ai API directly with Laravel's Http client — the surface area here is small enough that the wrapper may not earn its keep.
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.
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
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle