Как проверить адрес электронной почты с помощью регулярного выражения?

за эти годы я постепенно разработал регулярные выражения это правильно проверяет большинство адресов электронной почты, предполагая, что они не используют IP-адрес в качестве серверной части.

Я использую его в нескольких программах PHP, и это работает большую часть времени. Однако время от времени я связываюсь с кем-то, у кого возникают проблемы с сайтом, который его использует, и мне приходится вносить некоторые корректировки (совсем недавно я понял, что не разрешаю 4-символьный дву.)

какое лучшее регулярное выражение вы видели или видели для проверки электронных писем?

Я видел несколько решений, которые используют функции, использующие несколько более коротких выражений, но я бы предпочел иметь одно длинное сложное выражение в простой функции вместо нескольких коротких выражений в более сложной функции.

30 ответов


на полностью RFC 822 совместимый regex неэффективно и неясно из-за его длины. К счастью, RFC 822 был заменен дважды, и текущая спецификация для адресов электронной почты RFC 5322. RFC 5322 приводит к регулярному выражению, которое можно понять, если изучить в течение нескольких минут и достаточно эффективно для фактического использования.

один совместимый с RFC 5322 регулярных выражений можно найти в верхней части страницы http://emailregex.com/ но использует IP шаблон адреса, который плавает по интернету с ошибкой, которая позволяет 00 для любого из беззнаковых байтовых десятичных значений в адресе с разделителями-точками, что является незаконным. Остальная часть, по-видимому, согласуется с грамматикой RFC 5322 и проходит несколько тестов с использованием grep -Po, включая доменные имена, IP-адреса, плохие и имена учетных записей с кавычками и без них.

исправления 00 ошибка в шаблоне IP, мы получаем рабочее и довольно быстрое регулярное выражение. (Скрести отображаемая версия, а не уценка для фактического кода.)

(?:[а-З0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[а-З0-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])?|\[(?:(?:(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-z0-9 -]*[a-z0-9]:(?:[\x01 - \x08\x0b\x0c\x0e - \x1f\x21 - \x5a\x53 - \x7f]|\ \ [\x01-\x09\x0b\x0c\x0e - \x7f])+)\])

здесь - схемы of конечный автомат для выше regexp, который более ясен, чем сам regexp enter image description here

более сложные шаблоны в Perl и PCRE (библиотека регулярных выражений, используемая, например, в PHP) могут правильно разобрать RFC 5322 без заминки. Python и C# тоже могут это сделать, но они используют другой синтаксис, чем первые два. Однако, если вы вынуждены использовать один из многих менее мощных сопоставления языков, то это лучше всего использовать настоящий парсер.

также важно понимать, что проверка его на RFC не говорит вам абсолютно ничего о том, действительно ли этот адрес существует в поставляемом домене или является ли лицо, вводящее адрес, его истинным владельцем. Люди подписывают других в списки рассылки таким образом все время. Исправление, которое требует более причудливой проверки, которая включает в себя отправку этому адресу сообщения, включающего маркер подтверждения, предназначенный для ввода в том же интернете страница, как и адрес.

токены подтверждения-единственный способ узнать, что у вас есть адрес человека, который его вводит. Вот почему большинство списков рассылки теперь используют этот механизм для подтверждения регистрации. В конце концов, любой может поставить president@whitehouse.gov, и это даже будет разбираться как законное, но это вряд ли будет человек на другом конце.

для PHP, вы должны не используйте шаблон, указанный в проверьте адрес электронной почты с помощью PHP, правильный путь от цитирую:

существует некоторая опасность того, что общее использование и широко распространенное небрежное кодирование установят де-факто стандарт для адресов электронной почты, который является более ограничительным, чем зарегистрированный формальный стандарт.

это не лучше, чем все другие шаблоны без RFC. Он даже не достаточно умен, чтобы справиться даже RFC 822, не говоря уже о RFC 5322. этот, однако, есть.

если вы хотите получить фантазии и педантичен, реализовать полный двигатель состояния. Регулярное выражение может действовать только как элементарный фильтр. Проблема с регулярными выражениями заключается в том, что говорить кому-то, что их совершенно действительный адрес электронной почты недействителен (ложноположительный), потому что ваше регулярное выражение не может справиться с ним, просто грубо и невежливо с точки зрения пользователя. Механизм состояний для этой цели может проверять и даже корректировать адреса электронной почты, которые в противном случае считались бы недействительными при разборке адрес электронной почты в соответствии с каждым RFC. Это позволяет потенциально более приятный опыт, как

указанный адрес электронной почты "myemail@address, com" недопустим. Вы имели в виду ... myemail@address.com'?

см. также Проверка Адресов Электронной Почты, включая комментарии. Или сравнение адресов электронной почты проверка регулярных выражений.

Regular expression visualization

Debuggex Демо


вы не должны использовать регулярные выражения для проверки адресов электронной почты.

используйте MailAddress класс, как это:
try {
    address = new MailAddress(address).Address;
} catch(FormatException) {
    //address is invalid
}

класс MailAddress использует анализатор BNF для проверки адреса в полном соответствии с RFC822.

Если вы действительно хотите использовать регулярные выражения, здесь:

(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:
\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(
?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ 
\t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-
31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\
](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+
(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:
(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)
?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\
r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[
 \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)
?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t]
)*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[
 \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*
)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*)
*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+
|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r
\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:
\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t
]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1
]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](
?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?
:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?
:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\".\[\] 0-1]+(?:(?
:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?
[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\".\[\] 
0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|
\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>

@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"
(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\
".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?
:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[
\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\".\[\] 0-
1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(
?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;
:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([
^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\"
.\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\
]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\
[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\
r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 
0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]
|\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\".\[\] 
00-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\
.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,
;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?
:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*
(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".
\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[
^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]
]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(
?:(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\
".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(
?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[
\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t
])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t
])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?
:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|
\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*|(?:
[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\
]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)
?[ \t])*(?:@(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["
()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)
?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>

@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[
 \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,
;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\
".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?
(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".
\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:
\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[
"()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])
*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])
+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\
.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(
?:\r\n)?[ \t])*))*)?;\s*)

этот вопрос задают много, но я думаю, что вы должны отступить и спросить себя почему вы хотите проверить адреса электронной почты синтаксически? В чем на самом деле польза?

  • Он не будет ловить типичных опечаток.
  • Это не мешает людям вводить недействительные или выдуманные адреса электронной почты или вводить чужой адрес.

Если вы хотите проверить правильность электронной почты, у вас нет выбора, кроме как отправить подтверждение электронной почты и ответ пользователя на это. Во многих случаях вы есть отправить письмо с подтверждением в любом случае по соображениям безопасности или по этическим причинам (так что вы не можете, например, подписать кого-то на службу против их воли).


Это зависит от того, что вы подразумеваете под лучшей: Если вы говорите о ловле каждого действительного адреса электронной почты, используйте следующее:

(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:
\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(
?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ 
\t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-
31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\
](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+
(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:
(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)
?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\
r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[
 \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)
?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t]
)*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[
 \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*
)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*)
*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+
|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r
\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:
\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t
]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1
]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](
?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?
:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?
:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\".\[\] 0-1]+(?:(?
:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?
[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\".\[\] 
0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|
\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>
@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"
(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\
".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?
:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[
\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\".\[\] 0-
1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(
?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;
:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([
^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\"
.\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\
]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\
[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\
r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 
0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]
|\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\".\[\] 
00-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\
.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,
;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]]))|"(?
:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*
(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".
\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[
^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\]
]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(
?:(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\
".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(
?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[
\["()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t
])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t
])+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?
:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|
\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*|(?:
[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".\[\
]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)
?[ \t])*(?:@(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["
()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)
?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>
@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[
 \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,
;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\
".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?
(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\".
\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:
\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[
"()<>@,;:\".\[\]]))|"(?:[^\"\r\]|\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])
*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])
+|\Z|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*)(?:\
.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\".\[\] 0-1]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\".\[\]]))|\[([^\[\]\r\]|\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(
?:\r\n)?[ \t])*))*)?;\s*)

(http://www.ex-parrot.com / ~pdw/Mail-RFC822-Address.html) Если вы ищете что-то проще, но это поймает большинство действительных адресов электронной почты попробуйте что-то вроде:

"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"

изменить: Из ссылки:

это регулярное выражение будет проверять только адреса, у которых были удалены комментарии и заменяется пробелами (это делается модулем).


все зависит от того, насколько точно вы хотите быть. Для моих целей, где я просто пытаюсь держать вещи, как bob @ aol.com (пробелы в электронных письмах) или steve (нет домена) или mary@aolcom (нет периода раньше .com), я использую

/^\S+@\S+\.\S+$/

конечно, он будет соответствовать вещам, которые не являются действительными адресами электронной почты, но это вопрос игры правила 90/10.


[обновлено] я собрал все, что знаю о проверке адреса электронной почты здесь:http://isemail.info, который теперь не только проверяет, но и диагностирует проблемы с адресами электронной почты. Я согласен со многими комментариями здесь, что проверка является только частью ответа; см. мое эссе в http://isemail.info/about.

is_email () остается, насколько я знаю, единственным валидатором, который скажет вам окончательно, является ли данная строка действительным письмом адрес или нет. Я загрузил новую версию вhttp://isemail.info/

я сопоставил тестовые случаи от Кэла Хендерсона, Дэйва Чайлда, Фила Хака, Дуга Ловелла, RFC5322 и RFC 3696. 275 адресов во всех. Я провел все эти тесты против всех свободных валидаторов, которые смог найти.

Я постараюсь держать эту страницу в курсе, как люди улучшают свои валидаторы. Спасибо Кэлу, Майклу, Дейву, полу и Филу за помощь и сотрудничество в составлении этих тестов и конструктивная критика мой собственный валидатор.

люди должны знать о ошибки против RFC 3696 в частности. Три канонических примера на самом деле являются недопустимыми адресами. И максимальная длина адреса составляет 254 или 256 символов не 320.


Per спецификация W3C HTML5:

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

контекст:

A действующий e-mail адрес - строка, которая соответствует производству ABNF [...].

Примечание: это требование является злостное нарушение of RFC 5322, который определяет синтаксис для адресов электронной почты, который одновременно является слишком строгим (перед символом"@"), слишком расплывчатым (после символа"@") и слишком слабым (что позволяет комментарии, пробелы и цитируемые строки в манерах, незнакомых большинству пользователей), которые будут иметь практическое применение здесь.

следующее регулярное выражение, совместимое с JavaScript и Perl, является реализацией вышеуказанного определения.

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


Это легко в Perl 5.10 или новее:

/(?(DEFINE)
   (?<address>         (?&mailbox) | (?&group))
   (?<mailbox>         (?&name_addr) | (?&addr_spec))
   (?<name_addr>       (?&display_name)? (?&angle_addr))
   (?<angle_addr>      (?&CFWS)? < (?&addr_spec) > (?&CFWS)?)
   (?<group>           (?&display_name) : (?:(?&mailbox_list) | (?&CFWS))? ;
                                          (?&CFWS)?)
   (?<display_name>    (?&phrase))
   (?<mailbox_list>    (?&mailbox) (?: , (?&mailbox))*)

   (?<addr_spec>       (?&local_part) \@ (?&domain))
   (?<local_part>      (?&dot_atom) | (?&quoted_string))
   (?<domain>          (?&dot_atom) | (?&domain_literal))
   (?<domain_literal>  (?&CFWS)? \[ (?: (?&FWS)? (?&dcontent))* (?&FWS)?
                                 \] (?&CFWS)?)
   (?<dcontent>        (?&dtext) | (?&quoted_pair))
   (?<dtext>           (?&NO_WS_CTL) | [\x21-\x5a\x5e-\x7e])

   (?<atext>           (?&ALPHA) | (?&DIGIT) | [!#$%&'*+-/=?^_`{|}~])
   (?<atom>            (?&CFWS)? (?&atext)+ (?&CFWS)?)
   (?<dot_atom>        (?&CFWS)? (?&dot_atom_text) (?&CFWS)?)
   (?<dot_atom_text>   (?&atext)+ (?: \. (?&atext)+)*)

   (?<text>            [\x01-\x09\x0b\x0c\x0e-\x7f])
   (?<quoted_pair>     \ (?&text))

   (?<qtext>           (?&NO_WS_CTL) | [\x21\x23-\x5b\x5d-\x7e])
   (?<qcontent>        (?&qtext) | (?&quoted_pair))
   (?<quoted_string>   (?&CFWS)? (?&DQUOTE) (?:(?&FWS)? (?&qcontent))*
                        (?&FWS)? (?&DQUOTE) (?&CFWS)?)

   (?<word>            (?&atom) | (?&quoted_string))
   (?<phrase>          (?&word)+)

   # Folding white space
   (?<FWS>             (?: (?&WSP)* (?&CRLF))? (?&WSP)+)
   (?<ctext>           (?&NO_WS_CTL) | [\x21-\x27\x2a-\x5b\x5d-\x7e])
   (?<ccontent>        (?&ctext) | (?&quoted_pair) | (?&comment))
   (?<comment>         \( (?: (?&FWS)? (?&ccontent))* (?&FWS)? \) )
   (?<CFWS>            (?: (?&FWS)? (?&comment))*
                       (?: (?:(?&FWS)? (?&comment)) | (?&FWS)))

   # No whitespace control
   (?<NO_WS_CTL>       [\x01-\x08\x0b\x0c\x0e-\x1f\x7f])

   (?<ALPHA>           [A-Za-z])
   (?<DIGIT>           [0-9])
   (?<CRLF>            \x0d \x0a)
   (?<DQUOTE>          ")
   (?<WSP>             [\x20\x09])
 )

 (?&address)/x

Я использую

^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$

который используется в ASP.NET с помощью RegularExpressionValidator.


Не знаю о лучшем, но этот по крайней мере правильно, пока адреса имеют свои комментарии, разделенные и замененные пробелами.

серьезно. Для проверки электронной почты следует использовать уже написанную библиотеку. Лучший способ, вероятно, просто отправить электронное письмо с подтверждением на этот адрес.


адреса электронной почты, которые я хочу проверить, будут использоваться ASP.NET веб-приложение, использующее систему.Сеть.Пространство имен Mail для отправки писем списку людей. Поэтому вместо использования очень сложного регулярного выражения я просто пытаюсь создать экземпляр MailAddress из адреса. Mailaddress construtor выдаст исключение, если адрес сформирован неправильно. Таким образом, я знаю, что могу, по крайней мере, получить письмо из двери. Конечно, это проверка на стороне сервера, но в минимум, что тебе это нужно.

protected void emailValidator_ServerValidate(object source, ServerValidateEventArgs args)
{
    try
    {
        var a = new MailAddress(txtEmail.Text);
    }
    catch (Exception ex)
    {
        args.IsValid = false;
        emailValidator.ErrorMessage = "email: " + ex.Message;
    }
}

быстрый ответ

использовать следующее регулярное выражение для проверки ввода:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+

адреса, соответствующие этому регулярному выражению:

  • иметь локальную часть (т. е. часть перед знаком@), которая строго соответствует RFC 5321/5322,
  • иметь часть домена (т. е. часть после @-знака), которая является именем хоста с по крайней мере двумя метками, каждая из которых имеет не более 63 символов.

второй ограничение-это ограничение на RFC 5321/5322.

окончательный ответ

использование регулярного выражения, распознающего адреса электронной почты, может быть полезно в различных ситуациях: например, для сканирования адресов электронной почты в документе, для проверки ввода пользователем или в качестве ограничения целостности хранилища данных.

однако следует отметить, что если вы хотите узнать, действительно ли адрес относится к существующему почтовому ящику, нет никакой замены для отправки сообщение по адресу. Если вы хотите только проверить, является ли адрес грамматически правильным, Вы можете использовать регулярное выражение, но обратите внимание, что ""@[] является грамматически правильным адресом электронной почты, который, безусловно, не относится к существующему почтовому ящику.

синтаксис адресов электронной почты был определен в различных RFCs, особенно RFC 822 и RFC 5322. RFC 822 следует рассматривать как" оригинальный " стандарт, а RFC 5322-как последний норматив. Синтаксис, определенный в RFC 822, является наиболее мягким, и последующие стандарты ограничивали синтаксис все дальше и дальше, где новые системы или службы должны распознавать устаревший синтаксис, но никогда не производить его.

в этом ответе я возьму "адрес электронной почты", имея в виду addr-spec как определено в RFCs (т. е. jdoe@example.org, но не "John Doe"<jdoe@example.org>, nor some-group:jdoe@example.org,mrx@exampel.org;).

есть одна проблема с переводом синтаксисов RFC в regexes: синтаксисы не являются регулярными! Это поскольку они допускают необязательные комментарии в адресах электронной почты, которые могут быть бесконечно вложенными, в то время как бесконечное вложенность не может быть описано регулярным выражением. Для сканирования или проверки адресов, содержащих комментарии, необходим парсер или более мощные выражения. (Обратите внимание, что такие языки, как Perl, имеют конструкции для описания контекстно-свободных Грамматик в виде регулярных выражений.) В этом ответе я буду игнорировать комментарии и рассматривать только правильные регулярные выражения.

RFC определяют синтаксисы для сообщения электронной почты, а не для адресов электронной почты как таковой. Адреса могут отображаться в различных полях заголовка, и именно здесь они в первую очередь определены. Когда они появляются в полях заголовка, адреса могут содержать (между лексическими токенами) пробелы, комментарии и даже строки. Однако семантически это не имеет значения. Путем удаления этого пробела и т. д. из адреса вы получаете семантически эквивалентный каноническое представление. Таким образом, каноническое представление first. last (comment) @ [3.5.7.9] is first.last@[3.5.7.9].

различные синтаксисы должны использоваться для разных целей. Если вы хотите сканировать адреса электронной почты в (возможно, очень старом) документе, рекомендуется использовать синтаксис, определенный в RFC 822. С другой стороны, если вы хотите проверить пользовательский ввод, вы можете использовать синтаксис, определенный в RFC 5322, вероятно, только принимая канонические представления. Вы должны решить, какой синтаксис применим к вашему конкретному случаю.

я использую POSIX "расширенный" обычный выражения в этом ответе, предполагающие набор символов, совместимый с ASCII.

RFC 822

([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]))*(\\r)*")(\.([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]))*(\\r)*"))*@([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]))*(\\r)*])(\.([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]))*(\\r)*]))*

я считаю, что он полностью соответствует RFC 822, включая исправления. Он распознает только электронную почту обращения в канонической форме. Для регулярного выражения, которое распознает (складывание) пробелов, см. Вывод ниже.

вывод показывает, как я пришел к выражению. Я перечисляю все соответствующие правила грамматики из RFC точно так, как они появляются, а затем соответствующее регулярное выражение. Если ошибка была опубликована, я даю отдельное выражение для исправленного правила грамматики (с пометкой "ошибка") и использую обновленную версию в качестве подэкспрессии в последующих регулярных выражения.

как указано в пункте 3.1.4. в RFC 822 дополнительная линейная пробелы могут быть вставлены между лексем. Там, где это применимо, я расширил выражения, чтобы учесть это правило, и пометил результат "opt-lwsp".

CHAR        =  <any ASCII character>
            =~ .

CTL         =  <any ASCII control character and DEL>
            =~ [\x00-\x1F\x7F]

CR          =  <ASCII CR, carriage return>
            =~ \r

LF          =  <ASCII LF, linefeed>
            =~ \n

SPACE       =  <ASCII SP, space>
            =~  

HTAB        =  <ASCII HT, horizontal-tab>
            =~ \t

<">         =  <ASCII quote mark>
            =~ "

CRLF        =  CR LF
            =~ \r\n

LWSP-char   =  SPACE / HTAB
            =~ [ \t]

linear-white-space =  1*([CRLF] LWSP-char)
                   =~ ((\r\n)?[ \t])+

specials    =  "(" / ")" / "<" / ">" / "@" /  "," / ";" / ":" / "\" / <"> /  "." / "[" / "]"
            =~ [][()<>@,;:\".]

quoted-pair =  "\" CHAR
            =~ \.

qtext       =  <any CHAR excepting <">, "\" & CR, and including linear-white-space>
            =~ [^"\\r]|((\r\n)?[ \t])+

dtext       =  <any CHAR excluding "[", "]", "\" & CR, & including linear-white-space>
            =~ [^][\\r]|((\r\n)?[ \t])+

quoted-string  =  <"> *(qtext|quoted-pair) <">
               =~ "([^"\\r]|((\r\n)?[ \t])|\.)*"
(erratum)      =~ "(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*"

domain-literal =  "[" *(dtext|quoted-pair) "]"
               =~ \[([^][\\r]|((\r\n)?[ \t])|\.)*]
(erratum)      =~ \[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*]

atom        =  1*<any CHAR except specials, SPACE and CTLs>
            =~ [^][()<>@,;:\". \x00-\x1F\x7F]+

word        =  atom / quoted-string
            =~ [^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*"

domain-ref  =  atom

sub-domain  =  domain-ref / domain-literal
            =~ [^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*]

local-part  =  word *("." word)
            =~ ([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*")(\.([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*"))*
(opt-lwsp)  =~ ([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*")(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*"))*

domain      =  sub-domain *("." sub-domain)
            =~ ([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*])(\.([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*]))*
(opt-lwsp)  =~ ([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*])(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*]))*

addr-spec   =  local-part "@" domain
            =~ ([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*")(\.([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*"))*@([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*])(\.([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*]))*
(opt-lwsp)  =~ ([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*")((\r\n)?[ \t])*(\.((\r\n)?[ \t])*([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*")((\r\n)?[ \t])*)*@((\r\n)?[ \t])*([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*])(((\r\n)?[ \t])*\.((\r\n)?[ \t])*([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]|(\r\n)?[ \t]))*(\\r)*]))*
(canonical) =~ ([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]))*(\\r)*")(\.([^][()<>@,;:\". \x00-\x1F\x7F]+|"(\n|(\\r)*([^"\\r\n]|\[^\r]))*(\\r)*"))*@([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]))*(\\r)*])(\.([^][()<>@,;:\". \x00-\x1F\x7F]+|\[(\n|(\\r)*([^][\\r\n]|\[^\r]))*(\\r)*]))*

RFC 5322

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\[\t -~]))+")@([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*])

я считаю, что он полностью соответствует RFC 5322, включая исправления. Он распознает только адреса электронной почты в их канонической форме. Для регулярного выражения, которое распознает (складывание) пробелов, см. Вывод ниже.

вывод показывает, как я пришел к выражению. Я перечисляю все соответствующие правила грамматики из RFC точно так, как они появляются, а затем соответствующее регулярное выражение. Для правил которые включают семантически нерелевантные(складывающиеся) пробелы, я даю отдельное регулярное выражение с пометкой "(нормализованный)", которое не принимает этот пробел.

я проигнорировал все правила "obs -" из RFC. Это означает,что регексы соответствуют только адресам электронной почты, которые строго соответствуют RFC 5322. Если вам нужно сопоставить "старые" адреса (как это делает более свободная грамматика, включая правила "obs -"), вы можете использовать один из регулярных выражений RFC 822 из предыдущего абзаца.

VCHAR           =   %x21-7E
                =~  [!-~]

ALPHA           =   %x41-5A / %x61-7A
                =~  [A-Za-z]

DIGIT           =   %x30-39
                =~  [0-9]

HTAB            =   %x09
                =~  \t

CR              =   %x0D
                =~  \r

LF              =   %x0A
                =~  \n

SP              =   %x20
                =~  

DQUOTE          =   %x22
                =~  "

CRLF            =   CR LF
                =~  \r\n

WSP             =   SP / HTAB
                =~  [\t ]

quoted-pair     =   "\" (VCHAR / WSP)
                =~  \[\t -~]

FWS             =   ([*WSP CRLF] 1*WSP)
                =~  ([\t ]*\r\n)?[\t ]+

ctext           =   %d33-39 / %d42-91 / %d93-126
                =~  []!-'*-[^-~]

("comment" is left out in the regex)
ccontent        =   ctext / quoted-pair / comment
                =~  []!-'*-[^-~]|(\[\t -~])

(not regular)
comment         =   "(" *([FWS] ccontent) [FWS] ")"

(is equivalent to FWS when leaving out comments)
CFWS            =   (1*([FWS] comment) [FWS]) / FWS
                =~  ([\t ]*\r\n)?[\t ]+

atext           =   ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
                =~  [-!#-'*+/-9=?A-Z^-~]

dot-atom-text   =   1*atext *("." 1*atext)
                =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*

dot-atom        =   [CFWS] dot-atom-text [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*

qtext           =   %d33 / %d35-91 / %d93-126
                =~  []!#-[^-~]

qcontent        =   qtext / quoted-pair
                =~  []!#-[^-~]|(\[\t -~])

(erratum)
quoted-string   =   [CFWS] DQUOTE ((1*([FWS] qcontent) [FWS]) / FWS) DQUOTE [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  "([]!#-[^-~ \t]|(\[\t -~]))+"

dtext           =   %d33-90 / %d94-126
                =~  [!-Z^-~]

domain-literal  =   [CFWS] "[" *([FWS] dtext) [FWS] "]" [CFWS]
                =~  (([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  \[[\t -Z^-~]*]

local-part      =   dot-atom / quoted-string
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\[\t -~]))+"

domain          =   dot-atom / domain-literal
                =~  (([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?
(normalized)    =~  [-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*]

addr-spec       =   local-part "@" domain
                =~  ((([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?"(((([\t ]*\r\n)?[\t ]+)?([]!#-[^-~]|(\[\t -~])))+(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?)"(([\t ]*\r\n)?[\t ]+)?)@((([\t ]*\r\n)?[\t ]+)?[-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*(([\t ]*\r\n)?[\t ]+)?|(([\t ]*\r\n)?[\t ]+)?\[((([\t ]*\r\n)?[\t ]+)?[!-Z^-~])*(([\t ]*\r\n)?[\t ]+)?](([\t ]*\r\n)?[\t ]+)?)
(normalized)    =~  ([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\[\t -~]))+")@([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|\[[\t -Z^-~]*])

Примечание. что некоторые источники (в частности,W3C по) утверждают, что RFC 5322 слишком строг для локальной части (т. е. части перед знаком@). Это потому, что "..", "ля..Б " и " А " - это не допустимые точечные атомы, хотя они могут использоваться в качестве имен почтовых ящиков. Стандарт, однако, тут разрешить для локальных частей, как эти, за исключением того, что они должны быть процитированы. Так вместо a..b@example.net вы должны написать "a..b"@example.net, что семантически эквивалентно.

далее ограничения

SMTP (как определено в RFC 5321) дополнительно ограничивает набор допустимых адресов электронной почты (или фактически: имена почтовых ящиков). Кажется разумным ввести эту более строгую грамматику, чтобы соответствующий адрес электронной почты можно было использовать для отправки электронной почты.

RFC 5321 в основном оставляет в покое "локальную" часть (т. е. часть перед знаком@), но строже на части домена (т. е. часть после знака@). Это позволяет только имена хостов вместо точечные атомы и адресные литералы вместо доменных литералов.

грамматика, представленная в RFC 5321, слишком мягка, когда дело доходит до имен хостов и IP-адресов. Я взял на себя смелость "исправить" эти правила, используя этот проект и RFC 1034 в качестве руководящих принципов. Вот результирующее регулярное выражение.

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])

обратите внимание, что в зависимости от варианта использования вы не можете разрешить "общий адрес-литерал" в вашем регулярное выражение. Также обратите внимание, что я использовал отрицательный просмотр вперед (?!IPv6:) в последнем регулярном выражении, чтобы предотвратить" общий адрес-литерал " часть, чтобы соответствовать искаженным адресам IPv6. Некоторые процессоры регулярных выражений не поддерживают отрицательный lookahead. Удалить подстроку |(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+ из регулярного выражения, если вы хотите удалить всю часть "General-address-literal".

вот вывод:

Let-dig         =   ALPHA / DIGIT
                =~  [0-9A-Za-z]

Ldh-str         =   *( ALPHA / DIGIT / "-" ) Let-dig
                =~  [0-9A-Za-z-]*[0-9A-Za-z]

(regex is updated to make sure sub-domains are max. 63 charactes long - RFC 1034 section 3.5)
sub-domain      =   Let-dig [Ldh-str]
                =~  [0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?

Domain          =   sub-domain *("." sub-domain)
                =~  [0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*

Snum            =   1*3DIGIT
                =~  [0-9]{1,3}

(suggested replacement for "Snum")
ip4-octet       =   DIGIT / %x31-39 DIGIT / "1" 2DIGIT / "2" %x30-34 DIGIT / "25" %x30-35
                =~  25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9]

IPv4-address-literal    =   Snum 3("."  Snum)
                        =~  [0-9]{1,3}(\.[0-9]{1,3}){3}

(suggested replacement for "IPv4-address-literal")
ip4-address     =   ip4-octet 3("." ip4-octet)
                =~  (25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}

(suggested replacement for "IPv6-hex")
ip6-h16         =   "0" / ( (%x49-57 / %x65-70 /%x97-102) 0*3(%x48-57 / %x65-70 /%x97-102) )
                =~  0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}

(not from RFC)
ls32            =   ip6-h16 ":" ip6-h16 / ip4-address
                =~  (0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}

(suggested replacement of "IPv6-addr")
ip6-address     =                                      6(ip6-h16 ":") ls32
                    /                             "::" 5(ip6-h16 ":") ls32
                    / [                 ip6-h16 ] "::" 4(ip6-h16 ":") ls32
                    / [ *1(ip6-h16 ":") ip6-h16 ] "::" 3(ip6-h16 ":") ls32
                    / [ *2(ip6-h16 ":") ip6-h16 ] "::" 2(ip6-h16 ":") ls32
                    / [ *3(ip6-h16 ":") ip6-h16 ] "::"   ip6-h16 ":"  ls32
                    / [ *4(ip6-h16 ":") ip6-h16 ] "::"                ls32
                    / [ *5(ip6-h16 ":") ip6-h16 ] "::"   ip6-h16
                    / [ *6(ip6-h16 ":") ip6-h16 ] "::"
                =~  (((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::

IPv6-address-literal    =   "IPv6:" ip6-address
                        =~  IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)

Standardized-tag        =   Ldh-str
                        =~  [0-9A-Za-z-]*[0-9A-Za-z]

dcontent        =   %d33-90 / %d94-126
                =~  [!-Z^-~]

General-address-literal =   Standardized-tag ":" 1*dcontent
                        =~  [0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+

address-literal =   "[" ( IPv4-address-literal / IPv6-address-literal / General-address-literal ) "]"
                =~  \[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)]

Mailbox         =   Local-part "@" ( Domain / address-literal )
                =~  ([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)*|\[((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|IPv6:((((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){6}|::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){5}|[0-9A-Fa-f]{0,4}::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){4}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):)?(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){3}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,2}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){2}|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,3}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,4}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,5}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3})|(((0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}):){0,6}(0|[1-9A-Fa-f][0-9A-Fa-f]{0,3}))?::)|(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+)])

проверка ввода пользователем

общим случаем использования является проверка ввода пользователем, например HTML-форма. В этом случае обычно разумно исключить адресные литералы и потребовать по крайней мере две метки в имени хоста. Взяв за основу улучшенное регулярное выражение RFC 5321 из предыдущего раздела, полученное выражение будет:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\[\t -~]))+")@[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?(\.[0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?)+

я не рекомендую ограничивать локальную часть дальше, например, путем исключения цитируемых строк, поскольку мы не знаем, какие имена почтовых ящиков разрешают некоторые хосты (например,"a..b"@example.net или даже "a b"@example.net).

I также не рекомендуется явно проверять список литеральных доменов верхнего уровня или даже накладывать ограничения длины (помните, как ".музей " признан недействительным [a-z]{2,4}), но если нужно:

([-!#-'*+/-9=?A-Z^-~]+(\.[-!#-'*+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\[\t -~]))+")@([0-9A-Za-z]([0-9A-Za-z-]{0,61}[0-9A-Za-z])?\.)*(net|org|com|info| etc...)

убедитесь, что ваше регулярное выражение обновлено, если вы решили пойти по пути явной проверки домена верхнего уровня.

дополнительные соображения

при приеме только имен хостов в части домена (после @-sign), regexes выше принимают только метки с не более чем 63 символами, как они должны. Однако, они не используют тот факт, что имя хоста должно быть не более 253 символов (включая точки). Хотя это ограничение, строго говоря, все еще регулярное, невозможно сделать регулярное выражение, которое включает это правило.

еще одним соображением, особенно при использовании регулярных выражений для проверки ввода, является обратная связь с пользователем. Если пользователь вводит неверный адрес, было бы неплохо дать немного больше отзывов, чем простой "синтаксически неправильный адрес". С" ванильными " регексами это невозможно.

эти два соображения могут быть решены путем разбора адреса. Ограничение дополнительной длины для имен хостов в некоторых случаях также может быть устранено с помощью дополнительного регулярного выражения, которое проверяет его и сопоставляет адрес с обоими выражениями.

ни один из регулярных выражений в этом ответе не оптимизирован для производительности. Если производительность-это проблема, вы должны увидеть, можно ли (и как) оптимизировать регулярное выражение по вашему выбору.


есть много примеров этого в сети (и я думаю, что даже тот, который полностью проверяет RFC, но это десятки/сотни строк, если память служит). Люди, как правило, увлекаются проверкой такого рода вещей. Почему бы просто не проверить, что у него есть @ и хотя бы один . и встречает некоторую простую минимальную длину. Тривиально вводить поддельное электронное письмо и все равно соответствовать любому действительному регулярному выражению. Я бы предположил, что ложные срабатывания лучше, чем ложные срабатывания.


решая, какие символы разрешены, пожалуйста, помните своих апострофированных и дефисных друзей. Я не контролирую тот факт, что моя компания генерирует мой адрес электронной почты, используя мое имя из системы HR. Включая Апостроф в моей фамилии. Я не могу сказать вам, сколько раз я был заблокирован от взаимодействия с веб-сайтом тем, что мой адрес электронной почты "недействителен".


это регулярное выражение от Perl Email:: Valid библиотека. Я считаю, что это самый точный, он соответствует всем 822. И он основан на регулярном выражении в книге О'Рейли:

регулярное выражение, построенное на примере Джеффри Фридла в Использование Регулярных Выражений (http://www.ora.com/catalog/regexp/).

$RFC822PAT = <<'EOF';
[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\
xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xf
f\n5()]*)*\)[0\t]*)*(?:(?:[^(0)<>@,;:".\\[\]0-7\x80-\x
ff]+(?![^(0)<>@,;:".\\[\]0-7\x80-\xff])|"[^\\x80-\xff\n5
"]*(?:\[^\x80-\xff][^\\x80-\xff\n5"]*)*")[0\t]*(?:\([^\\x80-\
xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80
-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*
)*(?:\.[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\
\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\
x80-\xff\n5()]*)*\)[0\t]*)*(?:[^(0)<>@,;:".\\[\]0-7\x8
0-\xff]+(?![^(0)<>@,;:".\\[\]0-7\x80-\xff])|"[^\\x80-\xff\n
5"]*(?:\[^\x80-\xff][^\\x80-\xff\n5"]*)*")[0\t]*(?:\([^\\x
80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^
\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0
\t]*)*)*@[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([
^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\
\x80-\xff\n5()]*)*\)[0\t]*)*(?:[^(0)<>@,;:".\\[\]0-7\
x80-\xff]+(?![^(0)<>@,;:".\\[\]0-7\x80-\xff])|\[(?:[^\\x80-
\xff\n5\[\]]|\[^\x80-\xff])*\])[0\t]*(?:\([^\\x80-\xff\n5()
]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\
x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*(?:\.[
0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\
n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n\
015()]*)*\)[0\t]*)*(?:[^(0)<>@,;:".\\[\]0-7\x80-\xff]+(?!
[^(0)<>@,;:".\\[\]0-7\x80-\xff])|\[(?:[^\\x80-\xff\n5\[\
]]|\[^\x80-\xff])*\])[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\
x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n
5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*)*|(?:[^(0)<>@,;:".
\\[\]0-7\x80-\xff]+(?![^(0)<>@,;:".\\[\]0-7\x80-\xff]
)|"[^\\x80-\xff\n5"]*(?:\[^\x80-\xff][^\\x80-\xff\n5"]*)*")[^
()<>@,;:".\\[\]\x80-\xff0-02-7]*(?:(?:\([^\\x80-\xff\n
15()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][
^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)|"[^\\x80-\xff\
n5"]*(?:\[^\x80-\xff][^\\x80-\xff\n5"]*)*")[^()<>@,;:".\\[\]\
x80-\xff0-02-7]*)*<[0\t]*(?:\([^\\x80-\xff\n5()]*(?
:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-
\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*(?:@[0\t]*
(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5
()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()
]*)*\)[0\t]*)*(?:[^(0)<>@,;:".\\[\]0-7\x80-\xff]+(?![^(
40)<>@,;:".\\[\]0-7\x80-\xff])|\[(?:[^\\x80-\xff\n5\[\]]|\
[^\x80-\xff])*\])[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\
xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*
)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*(?:\.[0\t]*(?:\([^\\x80
-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x
80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t
]*)*(?:[^(0)<>@,;:".\\[\]0-7\x80-\xff]+(?![^(0)<>@,;:".\
\[\]0-7\x80-\xff])|\[(?:[^\\x80-\xff\n5\[\]]|\[^\x80-\xff])
*\])[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x
80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80
-\xff\n5()]*)*\)[0\t]*)*)*(?:,[0\t]*(?:\([^\\x80-\xff\n5(
)]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\
\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*@[0\t
]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n
15()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5
()]*)*\)[0\t]*)*(?:[^(0)<>@,;:".\\[\]0-7\x80-\xff]+(?![^(
0)<>@,;:".\\[\]0-7\x80-\xff])|\[(?:[^\\x80-\xff\n5\[\]]|
\[^\x80-\xff])*\])[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80
-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()
]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*(?:\.[0\t]*(?:\([^\\x
80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^
\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0
\t]*)*(?:[^(0)<>@,;:".\\[\]0-7\x80-\xff]+(?![^(0)<>@,;:".
\\[\]0-7\x80-\xff])|\[(?:[^\\x80-\xff\n5\[\]]|\[^\x80-\xff
])*\])[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\
\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x
80-\xff\n5()]*)*\)[0\t]*)*)*)*:[0\t]*(?:\([^\\x80-\xff\n5
()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\
\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*)?(?:[^
(0)<>@,;:".\\[\]0-7\x80-\xff]+(?![^(0)<>@,;:".\\[\]0-
7\x80-\xff])|"[^\\x80-\xff\n5"]*(?:\[^\x80-\xff][^\\x80-\xff\
n5"]*)*")[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|
\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))
[^\\x80-\xff\n5()]*)*\)[0\t]*)*(?:\.[0\t]*(?:\([^\\x80-\xff
\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\x
ff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*(
?:[^(0)<>@,;:".\\[\]0-7\x80-\xff]+(?![^(0)<>@,;:".\\[\]\
000-7\x80-\xff])|"[^\\x80-\xff\n5"]*(?:\[^\x80-\xff][^\\x80-\
xff\n5"]*)*")[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\x
ff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)
*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*)*@[0\t]*(?:\([^\\x80-\x
ff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-
\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)
*(?:[^(0)<>@,;:".\\[\]0-7\x80-\xff]+(?![^(0)<>@,;:".\\[\
]0-7\x80-\xff])|\[(?:[^\\x80-\xff\n5\[\]]|\[^\x80-\xff])*\]
)[0\t]*(?:\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-
\xff\n5()]*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\x
ff\n5()]*)*\)[0\t]*)*(?:\.[0\t]*(?:\([^\\x80-\xff\n5()]*(
?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]*(?:\[^\x80-\xff][^\\x80
-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)*\)[0\t]*)*(?:[^(0)<
>@,;:".\\[\]0-7\x80-\xff]+(?![^(0)<>@,;:".\\[\]0-7\x8
0-\xff])|\[(?:[^\\x80-\xff\n5\[\]]|\[^\x80-\xff])*\])[0\t]*(?:
\([^\\x80-\xff\n5()]*(?:(?:\[^\x80-\xff]|\([^\\x80-\xff\n5()]
*(?:\[^\x80-\xff][^\\x80-\xff\n5()]*)*\))[^\\x80-\xff\n5()]*)
*\)[0\t]*)*)*>)
EOF

когда вы пишете на PHP, я бы посоветовал вам использовать встроенную проверку PHP для электронных писем.

filter_var($value, FILTER_VALIDATE_EMAIL)

Если вы используете php-версию ниже 5.3.6, обратите внимание на эту проблему:https://bugs.php.net/bug.php?id=53091

Если вам нужна дополнительная информация о том, как работает эта проверка buid-in, см. здесь:действительно ли работает PHP filter_var FILTER_VALIDATE_EMAIL?


Кэл Хендерсон (Flickr) написал статью под названием разбор адресов электронной почты в PHP и показывает, как сделать правильный RFC (2)822-совместимый анализ адресов электронной почты. Вы также можете получить исходный код php, python и ruby, который является CC лицензию.


Я никогда не беспокоюсь о создании с моим собственным регулярным выражением, потому что есть вероятность, что кто-то другой уже придумал лучшую версию. Я всегда использую regexlib найти по душе.


нет ни одного, который действительно можно использовать.
Я обсуждаю некоторые вопросы в моем ответ на есть ли библиотека php для проверки адреса электронной почты?, это обсуждается также в Regexp распознавание адреса электронной почты трудно?

короче говоря, не ожидайте, что одно полезное регулярное выражение выполнит правильную работу. И лучшее регулярное выражение будет проверять синтаксис, а не действительность электронной почты (jhohn@example.com правильно, но он, вероятно, отскочит...).


одно простое регулярное выражение, которое, по крайней мере, не отклонит любой действительный адрес электронной почты, будет проверять что-то, за которым следует знак@, а затем что-то, за которым следует точка и, по крайней мере, 2 что-то. Он ничего не отклонит, но после просмотра спецификации я не могу найти никакого письма, которое было бы действительным и отклоненным.

email =~ /.+@[^@]+\.[^@]{2,}$/


вы можете использовать тот, который используется плагином проверки jQuery:

/^((([a-z]|\d|[!#$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i

для наиболее полной оценки лучшего регулярного выражения для проверки адреса электронной почты см. Эту ссылку;"сравнение адресов электронной почты проверка регулярных выражений"

вот текущее верхнее выражение для справочных целей:

/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i

не говоря уже о том, что нелатинские (китайский, арабский, греческий, иврит, кириллица и так далее) доменные имена должны быть разрешены в ближайшем будущем. Каждый должен изменить используемое регулярное выражение электронной почты, потому что эти символы, безусловно, не должны покрываться [a-z]/i, ни \w. Они все потерпят неудачу.

ведь лучшие способ проверить адрес электронной почты по-прежнему на самом деле отправить электронное письмо на указанный адрес для проверки адреса. Если адрес электронной почты является частью аутентификации пользователя (register/login/etc), то вы можете прекрасно сочетать его с системой активации пользователя. Т. е. отправьте письмо со ссылкой с уникальным ключом активации на указанный адрес электронной почты и разрешите войти только тогда, когда пользователь активировал вновь созданную учетную запись, используя ссылку в письме.

если цель регулярного выражения - просто быстро сообщить пользователю в пользовательском интерфейсе, что указанный адрес электронной почты не выглядит в правильном формате, лучше всего еще проверить, соответствует ли он в основном следующему регулярному выражению:

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

просто. Почему вы заботитесь о символах, используемых в имени и домене? Клиент несет ответственность за ввод действительного адреса электронной почты, а не сервера. Даже когда клиент входит в синтаксически действующий email адрес как aa@bb.cc, это не гарантирует, что это законный адрес электронной почты. Никто regex не может покрыть это.


на спецификация HTML5 предлагает простое регулярное выражение для проверки адреса электронной почты:

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

это намеренно не соответствует RFC 5322.

Примечание: это требование является злостное нарушение of RFC 5322, который определяет синтаксис для адресов электронной почты, который одновременно слишком строг (перед @ символ), слишком расплывчатый (после @ характер), и слишком слабый (позволяя комментариям, пробелам и цитируемым строкам в манерах, незнакомых большинству пользователей)быть практичными здесь.

общая длина также может быть ограничена 254 символами, за RFC 3696 errata 1690.


для яркой демонстрации следующий монстр довольно хорош, но все еще неправильно распознает все синтаксически допустимые адреса электронной почты:он распознает вложенные комментарии до четырех уровней.

это задание для синтаксического анализатора, но даже если адрес синтаксически допустим, он все равно может не быть доставлен. Иногда вам приходится прибегать к деревенскому методу "Эй, вы все, следите за нами!"

// derivative of work with the following copyright and license:
// Copyright (c) 2004 Casey West.  All rights reserved.
// This module is free software; you can redistribute it and/or
// modify it under the same terms as Perl itself.

// see http://search.cpan.org/~cwest/Email-Address-1.80/

private static string gibberish = @"
(?-xism:(?:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))
|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(?-xism:(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^
\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))
|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+
|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x
0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<DQ>(?-xism:(?-xism:[
^\<DQ>])|(?-xism:\(?-xism:[^\x0A\x0D])))+<DQ>(?-xism:(?-xi
sm:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xis
m:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\
]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\
s*)+|\s+)*))+)?(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?
-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[
^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*<(?-xism:(?-xi
sm:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^(
)\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(
?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))
|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<
>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]
+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))
|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:
(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s
*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?
:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x
0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xi
sm:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*
<DQ>(?-xism:(?-xism:[^\<DQ>])|(?-xism:\(?-xism:[^\x0A\x0D]
)))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\
]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-x
ism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+
)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:(
?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?
-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s
*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+(
?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism:
\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[
^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+)
)|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)
+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\
x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-x
ism:[^\[\]\])|(?-xism:\(?-xism:[^\x0A\x0D])))+)*\s*\](?-xi
sm:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:
\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(
?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+
)*\s*\)\s*)+|\s+)*)))>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-
xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\
s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^
\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))|(?-xism:(?-x
ism:(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^
()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*
(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D])
)|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()
<>\[\]:;@\,.<DQ>\s]+(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s
]+)*)(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+)
)|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism
:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\
s*\)\s*))+)*\s*\)\s*)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((
?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\
x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-x
ism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)
*<DQ>(?-xism:(?-xism:[^\<DQ>])|(?-xism:\(?-xism:[^\x0A\x0D
])))+<DQ>(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\
\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-
xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)
+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*))\@(?-xism:(?-xism:(?-xism:
(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(
?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[
^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\
s*\)\s*)+|\s+)*(?-xism:[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+
(?:\.[^\x00-\x1F\x7F()<>\[\]:;@\,.<DQ>\s]+)*)(?-xism:(?-xism
:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:
[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+
))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*
)+|\s+)*)|(?-xism:(?-xism:(?-xism:\s*\((?:\s*(?-xism:(?-xism
:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\(
(?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A
\x0D]))|)+)*\s*\)\s*))+)*\s*\)\s*)+|\s+)*\[(?:\s*(?-xism:(?-
xism:[^\[\]\])|(?-xism:\(?-xism:[^\x0A\x0D])))+)*\s*\](?-x
ism:(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism
:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:\s*(?-xism:(?-xism:
(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|)+)*\s*\)\s*))
+)*\s*\)\s*)+|\s+)*))))(?-xism:\s*\((?:\s*(?-xism:(?-xism:(?
>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0D]))|(?-xism:\s*\((?:
\s*(?-xism:(?-xism:(?>[^()\]+))|(?-xism:\(?-xism:[^\x0A\x0
D]))|)+)*\s*\)\s*))+)*\s*\)\s*)*)"
  .Replace("<DQ>", "\"")
  .Replace("\t", "")
  .Replace(" ", "")
  .Replace("\r", "")
  .Replace("\n", "");

private static Regex mailbox =
  new Regex(gibberish, RegexOptions.ExplicitCapture); 

вот PHP, который я использую. Я выбрал это решение в духе "ложные срабатывания лучше, чем ложные негативы", как заявил другой комментатор здесь и в отношении сохранения вашего времени ответа и загрузки сервера ... на самом деле нет необходимости тратить ресурсы сервера с регулярным выражением, когда это отсеет самую простую ошибку пользователя. Вы всегда можете следить за этим, отправив тестовое письмо, если хотите.

function validateEmail($email) {
  return (bool) stripos($email,'@');
}

согласно официальному стандарту RFC 2822 действительное регулярное выражение электронной почты

(?:[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])+)\])

Если вы хотите использовать его в Java, это действительно очень просто

import java.util.regex.*;

class regexSample 
{
   public static void main(String args[]) 
   {
      //Input the string for validation
      String email = "xyz@hotmail.com";

      //Set the email pattern string
      Pattern p = Pattern.compile(" (?:[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])+)\]");

      //Match the given string with the pattern
      Matcher m = p.matcher(email);

      //check whether match is found 
      boolean matchFound = m.matches();

      if (matchFound)
        System.out.println("Valid Email Id.");
      else
        System.out.println("Invalid Email Id.");
   }
}

стандарт RFC 5322:

разрешает локальную часть dot-atom, локальную часть с кавычками, устаревшую (смешанную dot-atom и quoted-string) локальную часть, домен доменного имени, (IPv4, IPv6 и IPv4-сопоставленный IPv6-адрес) доменный литеральный домен и (вложенные) CFWS.

'/^(?!(?>(?1)"?(?>\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD'

стандарт RFC 5321:

разрешает локальную часть dot-atom, локальную часть с кавычками, доменное имя и (IPv4, IPv6 и IPv4-сопоставленный IPv6-адрес) литерал домена домен.

'/^(?!(?>"?(?>\\[ -~]|[^"])"?){255,})(?!"?(?>\\[ -~]|[^"]){65,}"?@)(?>([!#-\'*+\/-9=?^-~-]+)(?>\.(?1))*|"(?>[ !#-\[\]-~]|\\[ -~])*")@(?!.*[^.]{64,})(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?2)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?3)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?3)(?>:(?3)){0,6})?::(?4)?))|(?>(?>IPv6:(?>(?3)(?>:(?3)){5}:|(?!(?:.*[a-f0-9]:){6,})(?5)?::(?>((?3)(?>:(?3)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?6)){3}))\])$/iD'

Basic:

разрешает локальную часть dot-atom и доменное имя домена (требуется по крайней мере две метки доменных имен с TLD, ограниченным 2-6 буквенными символами).

"/^(?!.{255,})(?!.{65,}@)([!#-'*+\/-9=?^-~-]+)(?>\.(?1))*@(?!.*[^.]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?\.){1,126}[a-z]{2,6}$/iD"

странно, что вы "не можете" разрешить 4 символа TLDs. Вы запрещаете людям .информация и .имя, и стоп ограничения длины .путешествие и .музей, Но да, они менее распространены, чем 2 символа TLDs и 3 символа TLDs.

вы должны разрешить заглавные буквы. Системы электронной почты нормализуют локальную и доменную части.

для вашего регулярного выражения из домена, доменное имя не может начинаться с '-' и не заканчивается '-'. Dash может оставаться только между ними.

Если вы использовали библиотеку PEAR, проверьте их почтовую функцию (забыли точное имя/библиотеку). Вы можете проверить адрес электронной почты, вызвав одну функцию, и она проверяет адрес электронной почты в соответствии с определением в RFC822.


public bool ValidateEmail(string sEmail)
{
    if (sEmail == null)
    {
        return false;
    }

    int nFirstAT = sEmail.IndexOf('@');
    int nLastAT = sEmail.LastIndexOf('@');

    if ((nFirstAT > 0) && (nLastAT == nFirstAT) && (nFirstAT < (sEmail.Length - 1)))
    {
        return (Regex.IsMatch(sEmail, @"^[a-z|0-9|A-Z]*([_][a-z|0-9|A-Z]+)*([.][a-z|0-9|A-Z]+)*([.][a-z|0-9|A-Z]+)*(([_][a-z|0-9|A-Z]+)*)?@[a-z][a-z|0-9|A-Z]*\.([a-z][a-z|0-9|A-Z]*(\.[a-z][a-z|0-9|A-Z]*)?)$"));
    }
    else
    {
        return false;
    }
}