diff --git a/src/Illuminate/Support/Str.php b/src/Illuminate/Support/Str.php index ee1547d4f002..bf5266069066 100644 --- a/src/Illuminate/Support/Str.php +++ b/src/Illuminate/Support/Str.php @@ -3,6 +3,8 @@ namespace Illuminate\Support; use Closure; +use Egulias\EmailValidator\EmailValidator; +use Egulias\EmailValidator\Validation\RFCValidation; use Illuminate\Support\Traits\Macroable; use JsonException; use League\CommonMark\Environment\Environment; @@ -2011,6 +2013,19 @@ public static function freezeUlids(?Closure $callback = null) return $ulid; } + /** + * Determine if a given value is a valid Email. + * + * @param mixed $value + * @return bool + */ + public static function isEmail(string $value): bool + { + $validator = new EmailValidator(); + + return $validator->isValid($value, new RFCValidation()); + } + /** * Remove all strings from the casing caches. * diff --git a/tests/Support/SupportStrTest.php b/tests/Support/SupportStrTest.php index 9f930a73250d..3e783941c355 100755 --- a/tests/Support/SupportStrTest.php +++ b/tests/Support/SupportStrTest.php @@ -1637,6 +1637,48 @@ public function testChopEnd() $this->assertSame($expected, Str::chopEnd($subject, $needle)); } } + + public function testValidEmails() + { + // Standard valid email formats according to RFC 5322 + $this->assertTrue(Str::isEmail('example@laravel.com')); + $this->assertTrue(Str::isEmail('user.name+alias@domain.co.uk')); + $this->assertTrue(Str::isEmail('123456@domain.com')); + $this->assertTrue(Str::isEmail('user@sub.domain.com')); + $this->assertTrue(Str::isEmail('a@b.co')); + $this->assertTrue(Str::isEmail('user@domain.org')); + $this->assertTrue(Str::isEmail('user_name@domain.com')); + $this->assertTrue(Str::isEmail('user-name@domain.io')); + $this->assertTrue(Str::isEmail('user@localhost')); + $this->assertTrue(Str::isEmail('user@123.123.123.123')); + $this->assertTrue(Str::isEmail('"user@name"@example.com')); + $this->assertTrue(Str::isEmail('"john.doe"@example.com')); + $this->assertTrue(Str::isEmail('very.common@example.com')); + $this->assertTrue(Str::isEmail('disposable.style.email.with+symbol@example.com')); + $this->assertTrue(Str::isEmail('user@domain.toolongtld')); + $this->assertTrue(Str::isEmail('user@domain.c')); + $this->assertTrue(Str::isEmail('user@[192.168.1.1]')); + + $this->assertFalse(Str::isEmail('plainaddress')); + $this->assertFalse(Str::isEmail('@missinglocal.com')); + $this->assertFalse(Str::isEmail('username@.com')); + $this->assertFalse(Str::isEmail('username@com.')); + $this->assertFalse(Str::isEmail('username@domain..com')); + $this->assertFalse(Str::isEmail('user@domain,com')); + $this->assertFalse(Str::isEmail('user@domain@another.com')); + $this->assertFalse(Str::isEmail('username@-domain.com')); + $this->assertFalse(Str::isEmail('username@domain-.com')); + $this->assertFalse(Str::isEmail('user@domain.com ')); + $this->assertFalse(Str::isEmail(' user@domain.com')); + $this->assertFalse(Str::isEmail('username@domain.com#')); + $this->assertFalse(Str::isEmail('username@domain..com')); + $this->assertFalse(Str::isEmail('user@sub..domain.com')); + $this->assertFalse(Str::isEmail('user@.com')); + $this->assertFalse(Str::isEmail('"user@name"@example..com')); + $this->assertFalse(Str::isEmail('user.@domain.com')); + $this->assertFalse(Str::isEmail('user..name@domain.com')); + $this->assertFalse(Str::isEmail('user@sub_domain.com')); + } } class StringableObjectStub