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 Email Domain Rule Laravel Package

h-farm/laravel-email-domain-rule

A Laravel validation rule for checking the domain of an email address. Allow or block specific domains, filter disposable or corporate emails, and get clear validation messages—drop it into form requests or validators with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require maize-tech/laravel-email-domain-rule:^3.2

There is nothing to publish, migrate, or boot. The package is a single validation rule, so the first place to look is src/EmailDomainRule.php — it is small enough to read end to end in five minutes, and doing so tells you exactly which constructor arguments exist and how subdomain matching is decided. Do that before wiring it into a FormRequest; it is faster than guessing from the README.

Minimal working use case — gate a B2B signup form to company domains:

use Maize\EmailDomainRule\EmailDomainRule;

$request->validate([
    'email' => [
        'required',
        'email',
        new EmailDomainRule(['acme.com', 'acme.io']),
    ],
]);

Confirm the constructor shape against the README for the exact tag you install (the rule can be driven either as an allow-list or as a deny-list depending on how it is instantiated), then write one Validator::make() test asserting both the pass and the fail path before shipping it into a form.

Upgrading from 3.1.x: 3.2.0 is purely PHP 8.3 and Laravel 11 compatibility — no API changes, no deprecations. Bump the constraint, run the suite, move on.

Implementation Patterns

Config-driven domain lists. Hardcoding domains in a FormRequest guarantees a deploy every time marketing adds a brand. Put the list in config instead:

// config/company.php
'email_domains' => array_filter(explode(',', env('ALLOWED_EMAIL_DOMAINS', 'acme.com'))),

Then a thin wrapper rule that composes the package rule keeps call sites clean and the list editable per environment:

final class CompanyEmail implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        $inner = new EmailDomainRule(config('company.email_domains'));
        // delegate, and re-word the failure for your product
    }
}

Deny-list mode for consumer providers. The inverse shape — allow everything except gmail.com, outlook.com, proton.me, plus a disposable-domain list — is the more common production case for B2B products. Keep that list in config, not in code, and expect it to be edited quarterly.

Subdomains are the usual surprise. Enterprise customers sign up from mail.acme.com or a regional subdomain. Decide explicitly whether a suffix match is acceptable, and encode that decision once in your wrapper rather than sprinkling variations across form requests.

Testing. Assert behaviour, not the package internals, with a dataset:

it('accepts company domains', function (string $email) {
    expect(Validator::make(['email' => $email], ['email' => ['required', 'email', new CompanyEmail]])->passes())->toBeTrue();
})->with(['[email protected]', '[email protected]']);

Layer with email:dns. The rule inspects the string only. If you also want to reject @acme.con typos, add Laravel's email:dns (or email:rfc,dns) alongside it — but keep it out of the test suite so tests stay offline.

Gotchas and Tips

  • Case sensitivity. Normalise with Str::lower() in your wrapper before comparing; Acme.com from a mobile keyboard otherwise fails silently. The same applies to trailing dots and whitespace.
  • Rules don't run on null. A missing field skips non-implicit rules entirely, so always pair with required (or nullable where intended) rather than relying on the domain rule to catch empty input.
  • Array fields. For multi-email inputs the rule receives an array and will misbehave — use email.* keys.
  • Split on the last @. If you write any derived logic (logging the rejected domain, say), use Str::afterLast($value, '@'); quoted local parts make the first @ unreliable.
  • No DNS resolution means typos are yours. A misspelled entry in an allow-list silently locks out an entire company and no one notices until support tickets arrive. Log rejections with the offending domain during rollout.
  • Custom error messages. Prefer rewording inside your own rule class over guessing the package's translation key in $request->validate([...], [...]) — the key is name-derived and brittle across versions.
  • bail and ordering. With bail, an invalid-format email never reaches the domain check; without it, users can see two errors at once. Pick deliberately for your UX.
  • IDN domains. Punycode (xn--…) and Unicode forms are different strings. If you serve non-Latin markets, normalise to punycode before comparing — this is not handled for you.
  • Config caching. Env-driven lists are frozen by php artisan config:cache; remember to re-cache in deploy scripts or the list will appear stale.
  • Laravel 11 slim skeleton. Config files are opt-in there; if the package ships one, vendor:publish it explicitly rather than assuming it exists.
  • Extension points. The rule is small and subclassing it is realistic; forking it is not. If you need heavier logic (per-tenant lists, database-backed domains), wrap it in your own ValidationRule and keep the dependency swappable.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings