regex - كيفية التحقق من صحة عنوان بريد إلكتروني باستخدام تعبير عادي؟




validation email (20)

على مر السنين طورت ببطء تعبيرًا عاديًا يثبت صحة عناوين البريد الإلكتروني MOST بشكل صحيح ، بافتراض عدم استخدام عنوان IP كجهاز الخادم.

أنا استخدمه في العديد من برامج PHP ، وهو يعمل في معظم الوقت. ومع ذلك ، من وقت لآخر ، أتصل بشخص يواجه مشكلة مع موقع يستخدمه ، وأنا في نهاية الأمر اضطر إلى إجراء بعض التعديلات (في الآونة الأخيرة أدركت أنني لم أكن تسمح بنطاقات TLD المكونة من 4 أحرف).

ما هو أفضل تعبير عادي لديك أو شاهدته للتحقق من صحة رسائل البريد الإلكتروني؟

لقد رأيت العديد من الحلول التي تستخدم الدالات التي تستخدم العديد من التعبيرات الأقصر ، لكنني أفضل أن يكون تعبيرًا واحدًا طويلًا في وظيفة بسيطة بدلاً من تعبير قصير قصير في وظيفة أكثر تعقيدًا.


جواب سريع

استخدم regex التالية للتحقق من صحة الإدخال:

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)*]))*

العناوين المتطابقة مع هذا التعبير العادي:

  • أن يكون لديك جزء محلي (أي الجزء قبل @ -sign) المتوافق تمامًا مع RFC 5321/5322 ،
  • امتلاك جزء مجال (أي الجزء بعد @ -sign) ، وهو اسم مضيف يحتوي على تسميقتين على الأقل ، يبلغ طول كل منهما 63 حرفًا على الأكثر.

القيد الثاني هو تقييد على RFC 5321/5322.

إجابة مفصلة

يمكن أن يكون استخدام تعبير عادي يتعرف على عناوين البريد الإلكتروني مفيدًا في مواقف مختلفة: على سبيل المثال للبحث عن عناوين البريد الإلكتروني في مستند ، أو للتحقق من صحة إدخال المستخدم ، أو كقيد تكامل في مستودع بيانات.

ومع ذلك ، يجب ملاحظة أنه إذا كنت تريد معرفة ما إذا كان العنوان يشير بالفعل إلى صندوق بريد موجود ، فلا يوجد بديل لإرسال رسالة إلى العنوان. إذا كنت تريد فقط التحقق مما إذا كان العنوان صحيحًا نحويًا ، فيمكنك استخدام تعبير عادي ، ولكن لاحظ أنه ""@[]عنوان بريد إلكتروني صحيح نحويًا لا يشير بالتأكيد إلى صندوق بريد موجود.

تم تعريف بنية عناوين البريد الإلكتروني في RFCs مختلفة ، وعلى الأخص RFC 822 و RFC 5322 . يجب أن ينظر إلى RFC 822 على أنه المعيار "الأصلي" و RFC 5322 كأحدث معيار. إن بناء الجملة المحدد في RFC 822 هو الأكثر تساهلاً والمعايير اللاحقة التي قيدت بناء الجملة أكثر وأكثر ، حيث ينبغي للأنظمة أو الخدمات الأحدث أن تتعرف على البنية القديمة ، ولكنها لا تنتجها أبدًا.

في هذا الجواب ، سأأخذ "عنوان البريد الإلكتروني" ليعني addr-specكما تم تعريفه في RFCs (أي [email protected]، ولكن ليس "John Doe"<[email protected]>، ولا some-group:[email protected],[email protected];).

هناك مشكلة واحدة في ترجمة جمل RFC إلى regexes: جمل الجملة ليست عادية! هذا لأنها تسمح بالتعليقات الاختيارية في عناوين البريد الإلكتروني التي يمكن أن تكون متداخلة بشكل لا نهائي ، بينما لا يمكن وصف التعشيش اللانهائي بالتعبير العادي. لإجراء مسح ضوئي لعناوين تحتوي على تعليقات أو التحقق منها ، تحتاج إلى تعبير أو تعبيرات أكثر قوة. (لاحظ أن لغات مثل بيرل لها بنى لوصف قواعد النحو الخالية من السياق بطريقة شبيهة للتعبير). في هذا الجواب سوف أتجاهل التعليقات وننظر فقط في التعبيرات العادية الصحيحة.

تحدد RFCs بُنى جمل رسائل البريد الإلكتروني ، وليس لعناوين البريد الإلكتروني على هذا النحو. قد تظهر العناوين في حقول رؤوس مختلفة وهذا هو المكان الذي يتم تعريفها في المقام الأول. عند ظهورها في عناوين حقول العناوين ، قد تحتوي (بين الرموز المميزة معنونة) على مسافة بيضاء ، والتعليقات ، بل وحتى فواصل الأسطر. لا يوجد دلالة مع ذلك. من خلال إزالة هذه المساحة البيضاء ، وما إلى ذلك من العنوان ، تحصل على تمثيل قانوني مكافئ دلالة . وبالتالي ، فإن التمثيل القانوني first. last (comment) @ [3.5.7.9]هو [email protected][3.5.7.9].

يجب استخدام البُنى المختلفة لأغراض مختلفة. إذا كنت تريد إجراء مسح ضوئي لعناوين البريد الإلكتروني في مستند (قد يكون قديمًا جدًا) ، فقد يكون من المفيد استخدام البنية كما هو محدد في RFC 822. من ناحية أخرى ، إذا كنت تريد التحقق من صحة إدخال المستخدم ، فقد ترغب في استخدام بناء الجملة كما هو محدد في RFC 5322 ، ربما فقط قبول التمثيل الكنسي. يجب أن تقرر أي صيغة تنطبق على حالتك المحددة.

أستخدم تعبيرات POSIX "الممتدة" العادية في هذا الجواب ، بافتراض مجموعة أحرف متوافقة مع ASCII.

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^-~]*])

أعتقد أنه متوافق تمامًا مع RFC 822 بما في ذلك errata . يتعرف فقط على عناوين البريد الإلكتروني في شكلها الأساسي. للتعبير المعتاد الذي يتعرف على (الطي) ، يمكنك الاطلاع على الاشتقاق أدناه.

يوضح الاشتقاق كيف وصلت إلى التعبير. أدرج جميع القواعد النحوية ذات الصلة من RFC تمامًا كما تظهر ، متبوعة بالتعريف المعتاد. عندما يتم نشر خطأ ما ، أعطي تعبيراً مستقلاً لقاعدة القواعد المصححة (تم وضع علامة "erratum") واستخدام النسخة المحدثة كتصريح فرعي في تعبيرات عادية لاحقة.

كما هو مذكور في الفقرة 3.1.4. من RFC 822 يمكن إدراج المسافة البيضاء الخطية الاختيارية بين الرموز المعجمية. حيثما أمكن ، قمت بتوسيع التعبيرات لتتوافق مع هذه القاعدة وقمت بتمييز النتيجة بـ "opt-lwsp".

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^-~]+)])

RFC 5322

لقد وصلت إلى التعبير العادي التالي. أدعو الجميع لمحاولة كسرها. إذا وجدت أي نتائج إيجابية خاطئة أو سلبية كاذبة ، فيرجى نشرها في تعليق وسأحاول إصلاح التعبير في أسرع وقت ممكن.

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

أعتقد أنه متوافق تمامًا مع RFC 5322 بما في ذلك errata . يتعرف فقط على عناوين البريد الإلكتروني في شكلها الأساسي. للتعبير المعتاد الذي يتعرف على (الطي) ، يمكنك الاطلاع على الاشتقاق أدناه.

يوضح الاشتقاق كيف وصلت إلى التعبير. أدرج جميع القواعد النحوية ذات الصلة من RFC تمامًا كما تظهر ، متبوعة بالتعريف المعتاد. بالنسبة للقواعد التي تتضمن مسافة بيضاء غير ملائمة (للطي) ، أعطي تعبيرًا عاديًا تم وضع علامة عليه "(طبيعي)" لا يقبل هذا الفراغ.

لقد تجاهلت جميع القواعد "obs -" من RFC. وهذا يعني أن التعبيرات العادية تتطابق فقط مع عناوين البريد الإلكتروني التي تتوافق تمامًا مع RFC 5322. إذا كان عليك مطابقة العناوين "القديمة" (حيث أن القواعد النحوية بما في ذلك قواعد "obs-") ، يمكنك استخدام أحد regexes RFC 822 من الفقرة السابقة.

filter_var($value, FILTER_VALIDATE_EMAIL)

لاحظ أن بعض المصادر (خاصة w3c ) تدعي أن RFC 5322 صارمة جدًا على الجزء المحلي (أي الجزء قبل @ -sign). وهذا بسبب ".." و "a..b" و "a". هي لا صالحة دوت الذرات، في حين أنها يمكن أن تستخدم كأسماء صندوق البريد. وRFC، ومع ذلك، لا يسمح لقطع المحلية مثل هذه، إلا أنها يجب أن تكون نقلت. لذا [email protected]يجب عليك بدلاً من أن تكتب "a..b"@example.net، وهو مكافئ لغويًا.

مزيد من القيود

كما أن SMTP (كما هو محدد في RFC 5321 ) يقيد مجموعة عناوين البريد الإلكتروني الصالحة (أو في الواقع: أسماء صناديق البريد). يبدو من المعقول فرض هذه القواعد الأكثر صرامة ، بحيث يمكن استخدام عنوان البريد الإلكتروني المتطابق بالفعل لإرسال بريد إلكتروني.

يترك RFC 5321 وحده الجزء "المحلي" (أي الجزء قبل @ -Sign) ، ولكنه أكثر صرامة على جزء المجال (أي الجزء بعد @ -sign). فهو يسمح فقط بأسماء المضيف بدلاً من ذرات النقاط ومعالجة القيم الحرفية بدلاً من القيم الحرفية للنطاق.

قواعد اللغة المقدمة في RFC 5321 متساهلة للغاية عندما يتعلق الأمر بكل من أسماء المضيفين وعناوين IP. حصلت على حرية "تصحيح" القواعد المعنية ، باستخدام هذا المسودة و 1034 RFC كمبادئ توجيهية. وإليك التعبير المعتاد الناتج.

/^((([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

لاحظ أنه اعتمادًا على حالة الاستخدام ، قد لا ترغب في السماح بـ "عام-العنوان الحرفي" في تعبيرك العادي. لاحظ أيضًا أنني استخدمت lookahead سلبيًا (?!IPv6:)في regex النهائي لمنع الجزء "العنوان العام للحرفي " لمطابقة عناوين IPv6 غير الصحيحة. بعض معالجات regex لا تدعم lookahead السلبية. قم بإزالة السلسلة الفرعية |(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+من regex إذا كنت تريد أخذ الجزء "عام - العنوان - حرفية" بالكامل خارج.

وهنا الاشتقاق:

/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~][email protected]((((([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

التحقق من إدخال المستخدم

حالة الاستخدام الشائعة هي التحقق من إدخال المستخدم ، على سبيل المثال في نموذج html. في هذه الحالة ، يكون من المعقول عادةً استبعاد حرفية العنوان وطلب تصنيفين على الأقل في اسم المضيف. عند استخدام تعبير R20 5321 المحسّن من القسم السابق كأساس ، يكون التعبير الناتج كالتالي:

([-!#-'*+/-9=?AZ^-~]+(\.[-!#-'*+/-9=?AZ^-~]+)*|"([]!#-[^-~ \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أو حتى "ab"@example.net).

لا أوصي أيضًا بالتحقق صراحةً من قائمة من نطاقات المستوى الأعلى الحرفية أو حتى فرض قيود الطول (تذكر كيف ".museum" تم إبطاله [az]{2,4}) ، ولكن إذا كان يجب عليك:

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

تأكد من تحديث تعبيرك المعتاد إذا قررت الانتقال إلى مسار التحقق من النطاق الأعلى الواضح.

مزيد من الاعتبارات

عند قبول أسماء المضيف فقط في جزء المجال (بعد @ -sign) ، فإن العبارات المعتادة أعلاه تقبل فقط التسميات التي تحتوي على 63 حرفًا على الأكثر ، كما ينبغي. ومع ذلك ، فإنها لا تفرض حقيقة أن اسم المضيف بالكامل يجب أن يكون على الأكثر 253 حرف (بما في ذلك النقاط). على الرغم من أن هذا القيد لا يزال منتظمًا بشكل صارم ، إلا أنه من غير المجدي تقديم تعبير عادي يتضمن هذه القاعدة.

هناك اعتبار آخر ، خاصة عند استخدام المعادلتين المنطقيتين للتحقق من صحة المدخلات ، وهو ملاحظات للمستخدم. إذا أدخل المستخدم عنوانًا غير صحيح ، فسيكون من الجميل تقديم تعليقات أكثر بقليل من مجرد "عنوان غير صحيح من الناحية النحوية". مع regexes "الفانيلا" هذا غير ممكن.

يمكن معالجة هذين الاعتبارين من خلال تحليل العنوان. يمكن في بعض الحالات أيضًا معالجة قيد الطول الإضافي على أسماء المضيف باستخدام regex إضافي يتحقق منه ، ومطابقة العنوان مع كل التعبيرات.

لم يتم تحسين أي من التعبيرات المنطقية في هذه الإجابة للأداء. إذا كان الأداء يمثل مشكلة ، يجب أن تعرف ما إذا كان (وكيف) يمكن تحسين التعبير المعتاد من اختيارك.


[تم تحديث] جمعت كل ما أعرفه حول التحقق من صحة عنوان البريد الإلكتروني هنا: http://isemail.info/ ، والذي لا يعمل الآن على التحقق من صحة المشكلات ولكن مع تشخيص عناوين البريد الإلكتروني. أوافق على العديد من التعليقات هنا بأن التحقق من الصحة ليس سوى جزء من الإجابة ؛ انظر مقالي على http://isemail.info/about .

يبقى is_email () ، بقدر ما أعرف ، المدقق الوحيد الذي سوف يخبرك بشكل نهائي ما إذا كانت سلسلة معينة عنوان بريد إلكتروني صالح أم لا. لقد قمت بتحميل إصدار جديد على http://isemail.info/

أنا جمعت حالات الاختبار من كال هندرسون ، ديف الطفل ، فيل Haack ، دوغ لوفل ، RFC5322 و RFC 3696. 275 عناوين الاختبار في كل شيء. أجريت كل هذه الاختبارات ضد جميع المدققين المجانيين الذين تمكنت من العثور عليهم.

سأحاول إبقاء هذه الصفحة محدّثة حيث يقوم الناس بتعزيز مدققيها. شكرا لكال ، مايكل ، ديف ، بول وفيل لمساعدتهم وتعاونهم في تجميع هذه الاختبارات والنقد البناء لمُصححي الخاص .

يجب أن يكون الناس على دراية بالمخططات ضد RFC 3696 على وجه الخصوص. ثلاثة من الأمثلة الأساسية هي في الواقع عناوين غير صالحة. والحد الأقصى لطول العنوان هو 254 أو 256 حرفًا وليس 320.


كل هذا يتوقف على مدى الدقة التي تريدها. لأغراضي ، حيث أحاول فقط منع أشياء مثل bob @ aol.com (مسافات في رسائل البريد الإلكتروني) أو steve (لا مجال على الإطلاق) أو [email protected] (بدون فترة قبل. com) ، أستخدم

/^\[email protected]\S+\.\S+$/

بالتأكيد ، ستطابق الأشياء التي ليست عناوين بريد إلكتروني صالحة ، ولكنها مسألة تشغيل قاعدة 90/10.


يتم طرح هذا السؤال كثيرًا ، ولكن أعتقد أنه يجب عليك الرجوع إلى الوراء وتسأل نفسك لماذا تريد التحقق من صحة عناوين البريد الإلكتروني بطريقة بناءة؟ ما هي الفائدة حقا؟

  • لن يصادف الأخطاء الشائعة.
  • لا يمنع الأشخاص من إدخال عناوين بريد إلكتروني غير صالحة أو مكتملة ، أو إدخال عنوان شخص آخر.

إذا كنت تريد التحقق من صحة رسالة البريد الإلكتروني ، فلن يكون أمامك خيار سوى إرسال رسالة تأكيد عبر البريد الإلكتروني وتزويد المستخدم بالرد على ذلك. في كثير من الحالات ، سيكون عليك إرسال رسالة تأكيد على أي حال لأسباب أمنية أو لأسباب أخلاقية (بحيث لا يمكنك مثلاً توقيع شخص ما إلى خدمة ضد إرادته).


يعتمد الأمر على ما تعنيه أنت الأفضل: إذا كنت تتحدث عن كل عنوان بريد إلكتروني صالح ، استخدم ما يلي:

(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:
\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(
?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ 
\t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\0
31]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\
](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+
(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:
(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z
|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)
?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\
r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[
 \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)
?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t]
)*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[
 \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*
)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t]
)+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)
*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+
|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r
\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:
\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t
]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031
]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](
?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?
:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?
:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)|(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?
:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?
[ \t]))*"(?:(?:\r\n)?[ \t])*)*:(?:(?:\r\n)?[ \t])*(?:(?:(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|
\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>
@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"
(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?
:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[
\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:[^()<>@,;:\\".\[\] \000-
\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(
?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)?[ \t])*(?:@(?:[^()<>@,;
:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([
^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\"
.\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\
]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\
[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\
r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] 
\000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]
|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?(?:[^()<>@,;:\\".\[\] \0
00-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\
.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,
;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?
:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*))*@(?:(?:\r\n)?[ \t])*
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t])*(?:[
^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\]
]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*\>(?:(?:\r\n)?[ \t])*)(?:,\s*(
?:(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(
?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[
\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t
])*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t
])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?
:\.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|
\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*|(?:
[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".\[\
]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)*\<(?:(?:\r\n)
?[ \t])*(?:@(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["
()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)
?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>
@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*(?:,@(?:(?:\r\n)?[
 \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,
;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\.(?:(?:\r\n)?[ \t]
)*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\
".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*))*)*:(?:(?:\r\n)?[ \t])*)?
(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\["()<>@,;:\\".
\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])*)(?:\.(?:(?:
\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])+|\Z|(?=[\[
"()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[ \t]))*"(?:(?:\r\n)?[ \t])
*))*@(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\r\n)?[ \t])
+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[ \t])*)(?:\
.(?:(?:\r\n)?[ \t])*(?:[^()<>@,;:\\".\[\] \000-\031]+(?:(?:(?:\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_.+-][email protected][a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"

تعديل: من الرابط:

سيؤدي هذا التعبير العادي إلى التحقق من صحة العناوين التي تم تجريد أي تعليقات منها واستبدالها بمسافة بيضاء (يتم ذلك بواسطة الوحدة النمطية).


يكون regex المتوافق مع RFC 822 بالكامل غير فعال وغامض بسبب طوله. لحسن الحظ ، تم استبدال RFC 822 مرتين وكانت المواصفة الحالية لعناوين البريد الإلكتروني هي RFC 5322 . RFC 5322 يؤدي إلى تعبير عادي يمكن فهمه إذا تمت دراسته لبضع دقائق وكفاءة كافية للاستخدام الفعلي.

يمكن العثور على واحدة regex متوافقة مع RFC 5322 في أعلى الصفحة في http://emailregex.com/ ولكن يستخدم نمط عنوان IP الذي يعوم حول الإنترنت مع خلل يسمح 00 لأي من القيم العشرية البايت غير الموقعة في عنوان نقطي ، وهو غير قانوني. يبدو أن باقي الأمر متوافق مع قواعد RFC 5322 ويمرر العديد من الاختبارات باستخدام grep -Po ، بما في ذلك أسماء نطاقات الحالات وعناوين IP والأسماء السيئة وأسماء الحسابات مع وبدون علامات اقتباس.

تصحيح الخطأ رقم 00 في نمط IP ، نحصل على regex سريع وعامل. (كشط النسخة التي تم تقديمها ، وليس العلامة التجارية ، للرمز الفعلي.)

(: [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]) | \ [(:( :( 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]) | [ على بعد Z0-9 -] * [A-Z0-9]: (؟: [\ x01- \ x08 \ x0b \ x0c \ x0e- \ x1f \ x21- \ x5a \ x53- \ x7f] | \\ [\ x01- \ X09 \ x0b \ x0c \ x0e- \ x7f]) +) \])

في ما يلي diagram لماكينة الحالة المحدودة لما هو فوق regexp وهو أكثر وضوحًا من regexp نفسه

يمكن للأنماط الأكثر تعقيدًا في Perl و PCRE (مكتبة regex المستخدمة على سبيل المثال في PHP) تحليل RFC 5322 بشكل صحيح دون حدوث أي عوائق . يمكن لبيثون و سي # أن يفعلوا ذلك أيضًا ، لكنهم يستخدمون صيغة مختلفة عن هاتين الأولين. ومع ذلك ، إذا تم إجبارك على استخدام واحدة من العديد من لغات مطابقة الأنماط الأقل قوة ، فمن الأفضل استخدام محلل حقيقي.

من المهم أيضًا أن تفهم أن التحقق من صحة ذلك في RFC لا يخبرك شيئًا على الإطلاق حول ما إذا كان هذا العنوان موجود بالفعل في النطاق المزود ، أو ما إذا كان الشخص الذي يدخل العنوان هو مالكه الحقيقي. الناس يوقعون الآخرين على القوائم البريدية بهذه الطريقة طوال الوقت. يتطلب الإصلاح الذي يتطلب نوعًا مرغوبًا من التحقق من الصحة إرسال هذا العنوان رسالة تشتمل على رمز تأكيد يُقصد إدخاله على نفس صفحة الويب كما كان العنوان.

الرموز المميزة للتأكيد هي الطريقة الوحيدة لمعرفة أنك حصلت على عنوان الشخص الذي يدخلها. هذا هو السبب في أن معظم القوائم البريدية تستخدم الآن تلك الآلية لتأكيد الاشتراكات. بعد كل شيء ، يمكن لأي شخص أن ينزل [email protected] @ [email protected] ، والتي سوف حتى تحليل قانوني ، ولكن ليس من المرجح أن يكون الشخص في الطرف الآخر.

بالنسبة لـ PHP ، يجب عدم استخدام النمط المعطى في التحقق من صحة عنوان البريد الإلكتروني مع PHP ، الطريق الصحيح الذي أقتبس منه:

هناك بعض الخطر من أن الاستخدام المشترك والتشفير على نطاق واسع سيحدد معيارًا فعليًا لعناوين البريد الإلكتروني الأكثر تقييدًا من المعيار الرسمي المسجل.

هذا ليس أفضل من جميع أنماط غير RFC الأخرى. انها ليست ذكية بما فيه الكفاية للتعامل حتى RFC 822 ، ناهيك عن RFC 5322. هذا واحد ، ومع ذلك ، هو.

إذا كنت ترغب في الحصول على الهوى والمتحمس ، وتنفيذ محرك دولة كاملة . يمكن للتعبير العادي أن يعمل فقط كمرشح بدائي. تكمن المشكلة في التعبيرات العادية في أن إخبار أحد الأشخاص أن عنوان البريد الإلكتروني الخاص به صالحًا تمامًا (غير صحيح) لأن تعبيرك العادي لا يمكنه التعامل معه ، هو أمر فظ وغير مهذب من وجهة نظر المستخدم. يمكن لمحرك الولاية لهذا الغرض التحقق من صحة عناوين البريد الإلكتروني أو حتى تصحيحها ، والتي يمكن اعتبارها غير صالحة لكونها تفكك عنوان البريد الإلكتروني وفقًا لكل RFC. هذا يسمح لتجربة ربما أكثر متعة ، مثل

عنوان البريد الإلكتروني المحدد 'myemail @ address، com' غير صالح. هل تقصد '[email protected]

راجع أيضًا التحقق من صحة عناوين البريد الإلكتروني ، بما في ذلك التعليقات. أو مقارنة عنوان البريد الإلكتروني التحقق من صحة التعبيرات العادية .

Debuggex Demo


وفقًا لمواصفات W3C HTML5 :

^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-][email protected][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])?)*$

سياق الكلام:

عنوان البريد الإلكتروني صالح هو سلسلة تتطابق مع الإنتاج ABNF […].

ملاحظة: يعد هذا المطلب انتهاكًا متعمدًا لـ RFC 5322 ، والذي يحدد بناء جملة لعناوين البريد الإلكتروني التي تكون صارمة في نفس الوقت (قبل الحرف "@") ، غامضة للغاية (بعد الحرف "@") ، والتراخي أيضًا ( السماح بالتعليقات ، وحروف المسافات البيضاء ، والسلاسل المقتبسة في سلوكيات غير مألوفة بالنسبة لمعظم المستخدمين) لتكون ذات فائدة عملية هنا.

التعبير العادي التالي JavaScript - و Perl متوافق مع تطبيق التعريف أعلاه.

/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-][email protected][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 قياسي:

يسمح المجال المحلي جزئياً بالجزء المحلي ، الجزئي المحلي المقتبس ، والجزء المحلي المتقلب (مختلط نقطة-ذرة وسلاسل-اقتباس) ، مجال اسم المجال ، (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-at ، والجزء الخاص بالسلسلة المقتبسة ، ومجال اسم المجال ، والمجال الحرفي للمجال (IPv4 ، و IPv6 ، وعنوان IPv4-mapped IPv6).

 '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!"?(?>\\\[ -~]|[^"]){65,}"[email protected])(?>([!#-\'*+\/-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' 

الأساسية:

يسمح المجال المحلي لنطاق dot-atom واسم المجال (الذي يتطلب على الأقل اثنين من تسميات أسماء النطاقات مع TLD محدودة إلى 2-6 أحرف أبجدية).

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

أنا أستعمل

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

وهو الذي استخدم في ASP.NET بواسطة RegularExpressionValidator.


للحصول على عرض توضيحي نابض بالحياة ، فإن الوحش التالي جيد جدًا ولكنه لا يتعرف بشكل صحيح على جميع عناوين البريد الإلكتروني الصحيحة من الناحية الحسابية: حيث يتعرف على التعليقات المتداخلة حتى عمق أربعة مستويات.

هذه وظيفة محلل ، ولكن حتى إذا كان العنوان صالحًا للبنية ، فقد لا يكون قابلاً للتسليم. في بعض الأحيان ، عليك اللجوء إلى أسلوب hillbilly "Hey، y'all، watch ee-us!"

'/^(?!(?>(?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'

أثناء تحديد الحروف المسموح بها ، يرجى تذكر أصدقائك المرتدين من طرف واحد والواحد. ليس لدي أي سيطرة على حقيقة أن شركتي تولد عنوان بريدي الإلكتروني باستخدام اسمي من نظام الموارد البشرية. يتضمن الفاصلة العليا في اسمي الأخير. لا يمكنني إخبارك بعدد المرات التي تم حظرها من التفاعل مع موقع ويب من خلال حقيقة أن عنوان بريدي الإلكتروني "غير صالح".


أنا لا أزعج ابدا خلق مع تعبير بلدي العادية ، لأن هناك احتمالات أن شخص آخر قد حان بالفعل مع نسخة أفضل. أنا دائما استخدام regexlib للعثور على واحد لتروق لي.


الغريب أنك "لا تستطيع" السماح بـ 4 أحرف TLDs. أنت تحظر على الأشخاص من .info و .name ، وتوقف تحديد الطول .travel و .museum ، ولكن نعم ، فهي أقل شيوعًا من 2 TLDs و 3 أحرف TLDs.

يجب عليك السماح بالحروف الأبجدية الكبيرة أيضًا. سوف أنظمة البريد الإلكتروني تطبيع الجزء المحلي والجزء المجال.

بالنسبة إلى regex الخاص بك من جزء المجال ، لا يمكن أن يبدأ اسم النطاق بـ "-" ولا يمكن أن ينتهي بـ "-". لا يمكن للدفعة أن تبقى إلا بين الدقائق.

إذا كنت تستخدم مكتبة PEAR ، تحقق من وظيفة البريد الخاصة بهم (نسيت الاسم / المكتبة). يمكنك التحقق من صحة عنوان البريد الإلكتروني عن طريق استدعاء وظيفة واحدة ، ويقوم بالتحقق من صحة عنوان البريد الإلكتروني وفقًا للتعريف الوارد في RFC822.


سيتم استخدام عناوين البريد الإلكتروني التي أريد التحقق منها بواسطة تطبيق ويب ASP.NET باستخدام مساحة الاسم System.Net.Mail لإرسال رسائل البريد الإلكتروني إلى قائمة بالأشخاص. لذلك ، بدلاً من استخدام تعبير عادي شديد التعقيد ، أحاول إنشاء مثيل MailAddress من العنوان. سيقوم موفر MailAddress بطرح استثناء إذا لم يتم تكوين العنوان بشكل صحيح. بهذه الطريقة ، أعلم أنه يمكنني على الأقل الحصول على البريد الإلكتروني من الباب. بالطبع هذا هو التحقق من جانب الخادم ولكن على الأقل تحتاج إلى ذلك على أي حال.

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;
    }
}

لا يوجد واحد وهو حقا قابلة للاستخدام.
أناقش بعض القضايا في جوابي على هل توجد مكتبة php للتحقق من صحة عنوان البريد الإلكتروني؟ ، وتناقش أيضا في الاعتراف Regexp عنوان البريد الإلكتروني من الصعب؟

باختصار ، لا تتوقع استخدام تعبير واحد قابل للاستخدام في وظيفة مناسبة. وأفضل تعبير منطقي سيثبت صحة الجملة وليس صحة البريد الإلكتروني ([email protected] صحيح ولكن من المحتمل أن ترتد ...).



هذا التعتيم هو من مكتبة Email::Valid بيرل . أعتقد أن هذا هو الأكثر دقة ، فهو يتطابق مع كل 822. وهو مبني على التعبير العادي في كتاب أورايلي:

التعبير العادي الذي تم إنشاؤه باستخدام مثال جيفري فريدل في تعبير التعبيرات العادية ( http://www.ora.com/catalog/regexp/ ).

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

هناك الكثير من الأمثلة على هذا على شبكة الإنترنت (وأعتقد أنه حتى واحد يصدق تماما RFC - لكنه عشرات / مئات خطوط طويلة إذا تخدم الذاكرة). يميل الناس لأن يميلوا إلى التحقق من صحة هذا النوع من الأشياء. لماذا لا تحقق فقط من وجود @ و واحد على الأقل. وتلبية بعض الحد الأدنى للطول البسيط. من البسيط إدخال بريد إلكتروني مزيف ولا يزال يتطابق مع أي regex صالح على أي حال. أعتقد أن الإيجابيات الكاذبة أفضل من السلبيات الكاذبة.


و تشير المواصفات HTML5 باستخدام التعابير المنطقية بسيط للتحقق من صحة عناوين البريد الإلكتروني:

import java.util.regex.*;

class regexSample 
{
   public static void main(String args[]) 
   {
      //Input the string for validation
      String email = "[email protected]";

      //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.");
   }
}

هذا عن قصد لا يتوافق مع 5322 .

ملاحظة: يعد هذا المطلب انتهاكًا متعمدًا لـ 5322 ، والذي يحدد بناء جملة لعناوين البريد الإلكتروني التي تكون في نفس الوقت صارمة جدًا (قبل @الحرف) ، وغامضة جدًا (بعد @الحرف) ، والتراخي أيضًا (السماح بالتعليقات ، وحروف المسافات البيضاء ، والسلاسل المقتبسة في سلوكيات غير مألوفة لمعظم المستخدمين) لتكون ذات فائدة عملية هنا.

يمكن أيضًا تحديد إجمالي الطول بـ 254 حرفًا لكل RFC 3696 errata 1690 .


وفقا لمعيار رسمي RFC 2822 البريد الإلكتروني صحيح regex هو

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

إذا كنت ترغب في استخدامه في جافا فإنه من السهل جدا حقا

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]+)*)[email protected][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;
    }
}






string-parsing