4309

Over the years I have slowly developed a regular expression that validates most email addresses correctly, assuming they don't use an IP address as the server part.

I use it in several PHP programs, and it works most of the time. However, from time to time I get contacted by someone that is having trouble with a site that uses it, and I end up having to make some adjustment (most recently I realized that I wasn't allowing four-character TLDs).

What is the best regular expression you have or have seen for validating emails?

I've seen several solutions that use functions that use several shorter expressions, but I'd rather have one long complex expression in a simple function instead of several short expression in a more complex function.

11
  • 12
    The regex that can validate that an IDNA is correctly formatted does not fit in stackexchange. (the rules on canonicalisation ate really tortuous and particularly ill-suited to regex processing) Commented Aug 29, 2017 at 23:51
  • 15
    Why you should not do this: Can it cause harm to validate email addresses with a regex? Commented Jan 9, 2018 at 14:30
  • The regexes may be variable as in some cases, an email con can contain a space, and in other times, it cannot contain any spaces. Commented Jul 23, 2018 at 4:21
  • You can check Symfonys regex for loose and strict check: github.com/symfony/symfony/blob/5.x/src/Symfony/Component/… Commented May 16, 2021 at 16:15
  • Using just regex can harm server security but if it is just as an input pattern, i suggest use this: stackoverflow.com/questions/5601647/… Commented Jun 7, 2021 at 21:42

78 Answers 78

1 2
3
1

I found a nice article, which says that the best way to validate e-mail address is the regular expression /.+@.+\..+/i.

Sign up to request clarification or add additional context in comments.

2 Comments

It doesn't match valid addresses like: me@localhost
It also matches invalid addresses like john doe@his domain.com.
1

For my purpose, I needed a way to also extract a display name if provided.
Thanks to the other answers and the regex provided on https://emailregex.com/ I came up with the following solution:

/^(?:([^<]*?)\s*<)?((?:[a-z0-9!#$%&'*+\/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+\/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))>?$/gi

This matches Display name (=group 1) + email address (=group 2).

Examples of matches:

[email protected]
john.o'[email protected]
John <[email protected]>
<[email protected]>
This is <[email protected]>

Tested with https://regex101.com/

Of course, as also mentioned in other answers, additional validation of the length of display name and email address is required (shouldn't exceed 320 UTF-8 bytes).

Comments

1

The world's most popular blogging platform WordPress uses this function to validate email address...

But they are doing it with multiple steps.

You don't have to worry anymore when using the regex mentioned in this function...

Here is the function...

/**
 * Verifies that an email is valid.
 *
 * Does not grok i18n domains. Not RFC compliant.
 *
 * @since 0.71
 *
 * @param string $email Email address to verify.
 * @param boolean $deprecated Deprecated.
 * @return string|bool Either false or the valid email address.
 */
function is_email( $email, $deprecated = false ) {
    if ( ! empty( $deprecated ) )
        _deprecated_argument( __FUNCTION__, '3.0' );

    // Test for the minimum length the email can be
    if ( strlen( $email ) < 3 ) {
        return apply_filters( 'is_email', false, $email, 'email_too_short' );
    }

    // Test for an @ character after the first position
    if ( strpos( $email, '@', 1 ) === false ) {
        return apply_filters( 'is_email', false, $email, 'email_no_at' );
    }

    // Split out the local and domain parts
    list( $local, $domain ) = explode( '@', $email, 2 );

    // LOCAL PART
    // Test for invalid characters
    if ( !preg_match( '/^[a-zA-Z0-9!#$%&\'*+\/=?^_`{|}~\.-]+$/', $local ) ) {
        return apply_filters( 'is_email', false, $email, 'local_invalid_chars' );
    }

    // DOMAIN PART
    // Test for sequences of periods
    if ( preg_match( '/\.{2,}/', $domain ) ) {
        return apply_filters( 'is_email', false, $email, 'domain_period_sequence' );
    }

    // Test for leading and trailing periods and whitespace
    if ( trim( $domain, " \t\n\r\0\x0B." ) !== $domain ) {
        return apply_filters( 'is_email', false, $email, 'domain_period_limits' );
    }

    // Split the domain into subs
    $subs = explode( '.', $domain );

    // Assume the domain will have at least two subs
    if ( 2 > count( $subs ) ) {
        return apply_filters( 'is_email', false, $email, 'domain_no_periods' );
    }

    // Loop through each sub
    foreach ( $subs as $sub ) {
        // Test for leading and trailing hyphens and whitespace
        if ( trim( $sub, " \t\n\r\0\x0B-" ) !== $sub ) {
            return apply_filters( 'is_email', false, $email, 'sub_hyphen_limits' );
        }

        // Test for invalid characters
        if ( !preg_match('/^[a-z0-9-]+$/i', $sub ) ) {
            return apply_filters( 'is_email', false, $email, 'sub_invalid_chars' );
        }
    }

    // Congratulations your email made it!
    return apply_filters( 'is_email', $email, $email, null );
}

1 Comment

This is too restrictive, it does not permit a quoted user component, and it does not support internationalized email addresses. Also the _deprecated_argument function is not defined.
1

As mentioned already, you can't validate an email with a regex. However, here's what we currently use to make sure user-input isn't totally bogus (forgetting the TLD, etc.).

This regex will allow IDN domains and special characters (like Umlauts) before and after the @ sign.

/^[\w.+-_]+@[^.][\w.-]*\.[\w-]{2,63}$/iu

1 Comment

What regular expression flavour and/or programming language? Perl? Something else?
1

List item

I use this function

function checkmail($value) {
    $value = trim($value);
    if (stristr($value,"@") &&
        stristr($value,".") &&
        (strrpos($value, ".") - stripos($value, "@") > 2) &&
        (stripos($value, "@") > 1) &&
        (strlen($value) - strrpos($value, ".") < 6) &&
        (strlen($value) - strrpos($value, ".") > 2) &&
        ($value == preg_replace('/[ ]/', '', $value)) &&
        ($value == preg_replace('/[^A-Za-z0-9\-_.@!*]/', '', $value))
    )
    {

    }
    else {
        return "Invalid Mail-Id";
    }
}

Comments

1

I converted the code into Java to match the compiler:

String pattern = "(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-zA-Z0-9-]*[a-zA-Z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])";

Comments

1

If you need a simple form to validate, you can use the answer of https://regexr.com/3e48o

^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$

let r = new RegExp(String.raw `^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$`);

//should be true
console.log(r.test('[email protected]'));
console.log(r.test('[email protected]'));
console.log(r.test('[email protected]'));

//should be false
console.log(r.test('@domain.tld'));
console.log(r.test('[email protected]'));
console.log(r.test('name@domain.'));
console.log(r.test('namedomain.tld'));
console.log(r.test(''));

//now that basic client-side validation is done, send a token from the server side to validate the user actually has access to the email

2 Comments

This regex is too simple and rejects ordinary valid emails. It incorrectly rejects the plus particle in the local part ([email protected]) and incorrectly rejects generic top-level domains with more than four letters ([email protected]).
This fails over validating .academy domains, for example
1

I'd like to propose my approach which is relatively simple while ensuring proper email structure and restricting forbidden characters. Valid for latin characters.

/^(?![\w\.@]*\.\.)(?![\w\.@]*\.@)(?![\w\.]*@\.)\w+[\w\.]*@[\w\.]+\.\w{2,}$/

2 Comments

This is the best one so far.
can you do this using golang?
1

if you are looking to check against a simple format: [email protected] or [email protected]

/^[^.\s@]+(\.[^.\s@]+)*@[^.\s@]+(\.[^.\s@]+)+$/

exact format used: ^x(.x)*@x(.x)+$

x any non-empty string without .(dot), \s(white space character) and @(at) in it

* repeat zero or more times

+ repeat one or more times

^ start of string

$ end of string

Comments

1

For database, version 23+, there is a built-in Usage Domain name email_d which uses the regex

^([a-zA-Z0-9!#$%&*+=?^_`{|}~-]+(\.[ A-Za-z0-9!#$%&*+=?^_`{|}~-]+)*)@(([ a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9] )?\.)+[a-zA-Z0-9]([a-zA-Z0-9-]*[a-z A-Z0-9])?)$

Of course, this is rather simplistic compared to the other answers, but... it is built-in.

Comments

1

We get a more practical implementation of RFC 5322 if we omit IP addresses, domain-specific addresses, the syntax using double quotes and square brackets. It will still match 99.99% of all email addresses in actual use today. Refer: https://www.regular-expressions.info/email.html

    private String REGEX_EMAIL_CHECK = "^[A-Za-z0-9!#%&'*+/=?^_`{|}~-]+(?:\\.[A-Za-z0-9!#%&'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?\\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?$";


    private boolean isValidEmailWithRegex(String email) {

        return email.matches(REGEX_EMAIL_CHECK);

    }


    public void testEmailAddressRegex() {
        // valid ?
        String[] validEmailAddresses = new String[] {
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "a%[email protected]",
                "[email protected]",
                "a~^[email protected]",
                "a~&[email protected]",
                "a*[email protected]",
                "[email protected]",
                "a~!#%^&*[email protected]",
                "a~!%^&*[email protected]",
                "a~%^&*[email protected]",
                "a~^&*[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "[email protected]",
                "abcdefghijklmnopqrstuvwxyz-abcdefghijklmnopqrstuvwxyz@example.com",

        };

        for (String email : validEmailAddresses) {
            System.out.println("Testing email address: " + email + " is valid");
            assertTrue(isValidEmailWithRegex(email));
        }

        // Invalid ?
        String[] invalidEmailAddresses = new String[] {
                "",
                " ",
                "@",
                "username",
                "username@example",
                "username@example.",
                "[email protected].",
                "username@example-com.",
                "[email protected].",
                "username@@example.com",
                "username@example@com",
                "[email protected]@",
                "[email protected]@example",
                "[email protected]@example.com",
                "[email protected]@example.com.",
                "[email protected]@example-com.",
                "[email protected]@example.com-.",
                "[email protected]@example.com.example",
                "[email protected]@example-com.example",
                "[email protected]@example.com-example",
        };

        for (String email : invalidEmailAddresses) {
            System.out.println("Testing email address: " + email + " is Invalid");
            assertFalse(isValidEmailWithRegex(email));
        }
    }

Comments

1

If you are looking for a more practical implementation, this is the regex used by Postmark for email validation, based on RFC5322:

[a-z0-9\.!#\$%&'`\*\+\-\/=\^_\{\}\|~]+@((\.)?[a-zA-Z0-9\-])+$

Source

Or escaped for an HTML input element pattern attribute (/v):

^[a-z0-9\.!#\$%&'`\*\+\-\\/=\^_\\{\\}\\|~]+@((\.)?[a-zA-Z0-9\\-])+$

Comments

0
^[_a-zA-Z0-9-]+(\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name))$

This matches 99.99% of email addresses, including some of the newer top-level-domain extensions, such as info, museum, name, etc. It also allows for emails tied directly to IP addresses.

Comments

0

Yet another option we have is to use DataAnnotations which has an EmailAddressAttribute. This can not only be applied to the property of a class but can also leveraged at runtime.

using System.ComponentModel.DataAnnotations;

Typical Usage

public class Person
{
    public int Id { get; set; }

    [EmailAddress]
    public string Email { get; set; }
}

At Runtime

var emailAddressAttribute = new EmailAddressAttribute();

if (emailAddressAttribute.IsValid("[email protected]"))
{
    //email is valid
}
else
{
    //email is invalid
}

Comments

0

You can use following regular expression for any email address:

^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$

For PHP

function checkEmailValidation($email)
{
    $expression = '/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/';
    if(preg_match($expression, $email))
    {
        return true;
    }
    else
    {
        return false;
    }
}

For JavaScript

function checkEmailValidation(email)
{
    var pattern = '/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/';
    if(pattern.test(email))
    {
        return true;
    }
    else
    {
        return false;
    }
}

1 Comment

if(preg_match($expression, $email)) { return true; } else { return false; } can be simplified to return (bool) preg_match($expression, $email);
0

The question title is fairly generic, however the body of the question indicates that it is about the PHP based solution. Will try to address both.

Generically speaking, for all programming languages: Typically, validating" an e-mail address with a reg-ex is something that any internet based service provider should desist from. The possibilities of kinds of domain names and e-mail addresses have increased so much in terms of variety, any attempt at validation, which is not well thought may end up denying some valid users into your system. To avoid this, one of the best ways is to send an email to the user and verify it being received. The good folks at "Universal Acceptance Steering Group" have compiled a languagewise list of libraries which are found to be compliant/non-compliant with various parameters involving validations vis-a-vis Internationalized Domain Names and Internationalized Email addresses. Please find the links to those documents over here and here.

Speaking specifically of PHP:

There is one good library available in PHP i.e. EmailValidator. It is an email address validator that includes many validation methods such as DNS validation. The validator specifically recommended is called RFCValidator and validates email addresses against several RFCs. It has good compliance when it comes to being inclusive towards IDNs and Internationalized Email addresses.

Comments

-3

This simple pattern works for me:

^(?<name>[^<>#()\.,;\s@\"]{1,})@(?<domain>[^<>#()\.,;\s@\"]{2,}\.(?<top>[^<>#()\.,;:\s@\"]{2,}))$

1 Comment

Welcome to Stack Overflow. If you decide to answer an older question that has well established and correct answers, adding a new answer late in the day may not get you any credit. If you have some distinctive new information, or you're convinced the other answers are all wrong, by all means add a new answer, but 'yet another answer' giving the same basic information a long time after the question was asked usually won't earn you much credit. It also isn't entirely clear which dialect of regex you are using.
-3

The regular expression that I use:

[\w-+]+([.][\w]+)?@[\w-+]+([.][a-z]{2,})+

Comments

1 2
3

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.