Come convalidare un indirizzo e-mail usando un'espressione regolare?


3314

Nel corso degli anni ho lentamente sviluppato un'espressione regolare che convalida correttamente la maggior parte degli indirizzi e-mail, supponendo che non utilizzino un indirizzo IP come parte del server.

Lo uso in diversi programmi PHP e funziona il più delle volte. Tuttavia, di tanto in tanto vengo contattato da qualcuno che ha problemi con un sito che lo utilizza e finisco per dover apportare alcune modifiche (di recente mi sono reso conto che non stavo permettendo TLD a 4 caratteri).

Qual è la migliore espressione regolare che hai o hai visto per convalidare le email?

Ho visto diverse soluzioni che utilizzano funzioni che utilizzano diverse espressioni più brevi, ma preferirei avere un'espressione lunga e complessa in una funzione semplice anziché diverse espressioni brevi in ​​una funzione più complessa.



5
Il regex che può confermare che un IDNA è formattato correttamente non si adatta allo stackexchange. (le regole sulla canonicalizzazione mangiarono davvero tortuose e particolarmente inadatte all'elaborazione del regex)
Jasen,


Le regex possono essere variabili in quanto in alcuni casi, un indirizzo e-mail può contenere uno spazio e in altre volte non può contenere spazi.
Ṃųỻịgǻňạcểơửṩ,

Risposte:


2440

Il regex completamente conforme RFC 822 è inefficiente e oscuro a causa della sua lunghezza. Fortunatamente, RFC 822 è stato sostituito due volte e l'attuale specifica per gli indirizzi e-mail è RFC 5322 . RFC 5322 porta a una regex che può essere compresa se studiata per alcuni minuti ed è abbastanza efficiente per l'uso effettivo.

Un regex conforme a RFC 5322 è disponibile nella parte superiore della pagina all'indirizzo http://emailregex.com/ ma utilizza il modello di indirizzo IP che fluttua su Internet con un bug che consente 00uno qualsiasi dei valori decimali di byte senza segno in un indirizzo delimitato da punti, che è illegale. Il resto sembra coerente con la grammatica RFC 5322 e supera diversi test utilizzando grep -Po, tra cui nomi di dominio di casi, indirizzi IP, nomi errati e nomi di account con e senza virgolette.

Correggendo il 00bug nel modello IP, otteniamo un regex funzionante e abbastanza veloce. (Raschia la versione renderizzata, non il markdown, per il codice reale.)

(: [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]) |? [ a-z0-9 -] * [a-z0-9]: (:? [\ x01- \ x08 \ x0b \ x0c \ x0e- \ x1f \ x21- \ X5a \ x53- \ x7F] | \\ [\ x01- \ x09 \ x0b \ x0c \ x0e- \ x7F]) +) \])

o:

(?:[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])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

Ecco il diagramma della macchina a stati finiti per regexp sopra che è più chiaro di regexp stesso inserisci qui la descrizione dell'immagine

I modelli più sofisticati in Perl e PCRE (libreria regex utilizzata ad esempio in PHP) possono analizzare correttamente RFC 5322 senza intoppi . Anche Python e C # possono farlo, ma usano una sintassi diversa da quelle dei primi due. Tuttavia, se sei costretto a utilizzare uno dei molti linguaggi di corrispondenza dei modelli meno potenti, è meglio utilizzare un vero parser.

È anche importante capire che la convalida per RFC non ti dice assolutamente nulla sul fatto che quell'indirizzo esista effettivamente nel dominio fornito o se la persona che inserisce l'indirizzo sia il suo vero proprietario. Le persone iscrivono gli altri alle mailing list in questo modo per tutto il tempo. Una correzione che richiede un tipo di convalida più elaborato che comporta l'invio a quell'indirizzo di un messaggio che include un token di conferma destinato a essere immesso nella stessa pagina Web dell'indirizzo.

I token di conferma sono l'unico modo per sapere che hai l'indirizzo della persona che lo ha inserito. Questo è il motivo per cui la maggior parte delle mailing list ora utilizza questo meccanismo per confermare le iscrizioni. Dopotutto, chiunque può sminuire president@whitehouse.gov, e ciò analizzerà persino come legale, ma non è probabile che sia la persona all'altro capo.

Per PHP, è necessario non utilizzare il modello dato in Convalida di un indirizzo e-mail con PHP, il modo giusto da cui cito:

Esiste il pericolo che l'uso comune e la diffusa codificazione sciatta stabiliscano uno standard di fatto per gli indirizzi di posta elettronica che è più restrittivo rispetto allo standard formale registrato.

Questo non è migliore di tutti gli altri schemi non RFC. Non è nemmeno abbastanza intelligente da gestire anche RFC 822 , figuriamoci RFC 5322. Questo , tuttavia, lo è.

Se vuoi diventare sofisticato e pedante, implementa un motore statale completo . Un'espressione regolare può agire solo come filtro rudimentale. Il problema con le espressioni regolari è che dire a qualcuno che il loro indirizzo e-mail perfettamente valido non è valido (un falso positivo) perché la tua espressione regolare non può gestirlo è maleducato e scortese dal punto di vista dell'utente. Un motore di stato allo scopo può sia convalidare che persino correggere indirizzi e-mail che altrimenti verrebbero considerati non validi in quanto smontano l'indirizzo e-mail in base a ciascun RFC. Ciò consente un'esperienza potenzialmente più piacevole, come

L'indirizzo e-mail specificato "myemail @ address, com" non è valido. Intendevi "myemail@address.com"?

Vedi anche Convalida degli indirizzi e-mail , inclusi i commenti. O confrontare l'indirizzo e-mail che convalida le espressioni regolari .

Visualizzazione delle espressioni regolari

Debuggex Demo


180
Hai detto "Non esiste una buona espressione regolare". Questo è generale o specifico per la convalida dell'indirizzo e-mail?
Tomalak,

37
@Tomalak: solo per indirizzi e-mail. Come ha detto bortzmeyer, la RFC è estremamente complicata
Luk,

37
L'articolo del diario di Linux che menzioni è di fatto errato sotto diversi aspetti. In particolare Lovell chiaramente non ha letto gli errata su RFC3696 e ripete alcuni degli errori nella versione pubblicata di RFC. Altro qui: dominicsayers.com/isemail
Dominic Sayers

9
Jeff Atwood ha un bel regex in questo post del blog per convalidare tutti gli indirizzi e-mail validi: codinghorror.com/blog/2005/02/regex-use-vs-regex-abuse.html
CMircea

5
Si noti che le attuali specifiche HTML5 includono un regex e un ABNF per la convalida dell'input di tipo e-mail deliberatamente più restrittivo rispetto agli RFC originali.
Synchro,

747

Non utilizzare espressioni regolari per convalidare gli indirizzi e-mail.

Utilizzare invece la classe MailAddress , in questo modo:

try {
    address = new MailAddress(address).Address;
} catch(FormatException) {
    // address is invalid
}

La MailAddressclasse utilizza un parser BNF per convalidare l'indirizzo in piena conformità con RFC822.

Se si prevede di utilizzare il MailAddressper convalidare l'indirizzo e-mail, tenere presente che questo approccio accetta anche la parte del nome visualizzato dell'indirizzo e-mail e che potrebbe non essere esattamente ciò che si desidera ottenere. Ad esempio, accetta queste stringhe come indirizzi di posta elettronica validi:

  • "user1@hotmail.com; user2@gmail.com"
  • "user1@hotmail.com; user2@gmail.com; user3@company.com"
  • "Nome visualizzato utente user3@company.com"
  • "user4 @ company.com"

In alcuni di questi casi, solo l'ultima parte delle stringhe viene analizzata come indirizzo; il resto prima è il nome visualizzato. Per ottenere un semplice indirizzo e-mail senza alcun nome visualizzato, è possibile verificare l'indirizzo normalizzato rispetto alla stringa originale.

bool isValid = false;

try
{
    MailAddress address = new MailAddress(emailAddress);
    isValid = (address.Address == emailAddress);
    // or
    // isValid = string.IsNullOrEmpty(address.DisplayName);
}
catch (FormatException)
{
    // address is invalid
}

Inoltre, un indirizzo con un punto alla fine, come user@company.è accettato anche da MailAddress.

Se vuoi davvero usare un regex, eccolo qui :

(?: (?: \ 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 *)

26
Scoprirai che la classe MailAddress in .NET 4.0 è di gran lunga migliore nella convalida degli indirizzi e-mail rispetto alle versioni precedenti. Ho apportato alcuni miglioramenti significativi ad esso.
Jeff Tucker,

7
Penso che in un certo senso ... non funzioni ... per ID più semplici. a @ b non convalida. ar@b.com corrisponde solo fino ad ar @ b, il .com non corrisponde. Tuttavia, qualcosa come "I am me" @ [10.10.10.10] funziona! :)
Raze,

5
Tieni presente che questi validatori regex conformi a RFC lasceranno passare molti indirizzi email che probabilmente non vorresti accettare come "a <body / onload = alert (' lol.com?'+document.cookies ) @aa> "che è un indirizzo e-mail valido nell'e-mail :: valido di perl (che utilizza quell'enorme regex) e che può essere sfruttato per XSS rt.cpan.org/Public/Bug/Display.html?id=75650
Matthew Lock,

9
@MatthewLock: non è peggio di fake@not-a-real-domain.name. Non è necessario fare affidamento sulla convalida della posta elettronica per impedire XSS.
SLaks,

10
@MatthewLock: No. È necessario evitare le query SQL (o, meglio ancora, utilizzare i parametri). La sanificazione non è una difesa adeguata.
SLaks

536

Questa domanda viene posta molto, ma penso che dovresti fare un passo indietro e chiederti perché vuoi convalidare sinteticamente gli indirizzi e-mail? Qual è il vantaggio davvero?

  • Non prenderà errori di battitura comuni.
  • Non impedisce alle persone di inserire indirizzi e-mail non validi o inventati o di inserire l'indirizzo di qualcun altro.

Se si desidera convalidare che un'e-mail è corretta, non si ha altra scelta che inviare un'e-mail di conferma e far rispondere l'utente. In molti casi si hanno di inviare una mail di conferma in ogni caso per motivi di sicurezza o per motivi etici (quindi non è possibile per esempio segno qualcuno per un servizio contro la loro volontà).


92
Potrebbe valere la pena verificare che abbiano inserito qualcosa @ qualcosa nel campo in una convalida lato client solo per rilevare semplici errori - ma in generale hai ragione.
Martin Beckett,

8
Martin, ti ho dato un +1, solo per leggere in seguito che foobar @ dk è un'e-mail valida. Non sarebbe carino, ma se vuoi essere sia conforme alla RFC sia usare il buon senso, dovresti rilevare casi come questo e chiedere all'utente di confermare che è corretto.
Philfreo,

106
@olavk: se qualcuno inserisce un errore di battitura (ad es .:) me@hotmail, ovviamente non riceverà l'e-mail di conferma, e quindi dove si trova? Non sono più sul tuo sito e si chiedono perché non possano registrarsi. In realtà no, non lo sono - si sono completamente dimenticati di te. Tuttavia, se potessi semplicemente fare un controllo di integrità di base con una regex mentre sono ancora con te, allora possono rilevare immediatamente quell'errore e hai un utente felice.
nickf

5
@JacquesB: fai un punto eccellente. Solo perché passa l'adunata per RFC non significa che sia davvero l'indirizzo di quell'utente. Altrimenti tutti quegli president@whitehouse.govindirizzi indicano un comandante in capo molto netbusy. :)
tchrist

39
Non deve essere bianco o nero. Se l'e-mail sembra errata, avvisare l'utente. Se l'utente desidera continuare, lascialo. Non forzare l'utente a conformarsi al tuo regex, piuttosto, usa regex come strumento per aiutare l'utente a sapere che potrebbe esserci un errore.
ninjaneer,

354

Tutto dipende da quanto preciso vuoi essere. Per i miei scopi, dove sto solo cercando di tenere fuori cose come bob @ aol.com(spazi nelle e-mail) o steve(nessun dominio) o mary@aolcom(nessun periodo prima di .com), utilizzo

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

Certo, corrisponderà a cose che non sono indirizzi e-mail validi, ma si tratta di ottenere semplici errori comuni.

Ci sono un numero qualsiasi di modifiche che possono essere apportate a quella regex (e alcune sono nei commenti per questa risposta), ma è semplice, facile da capire ed è un ottimo primo tentativo.


6
Non corrisponde a foobar @ dk che è un indirizzo e-mail valido e funzionante (anche se probabilmente la maggior parte dei server di posta non lo accetteranno o aggiungeranno qualcosa.com.)
bortzmeyer

3
Si lo farà. Ti suggerisco di provarlo tu stesso. $ perl -le'print q{foo@bar.co.uk} = ~ /^\S+@\S+\.\S+$/? q {Y}: q {N} '
Andy Lester,

7
@Richard: .è incluso in \S.
David Thornley,

43
JJJ: Sì, corrisponderà a molte schifezze. Abbinerà & $ * # $ (@ $ 0 (%)) $ #.) & *) (* $, Anche. * Per me, sono più preoccupato di catturare l'errore di battitura del dito fumble dispari come mary@aolcomse fossi spazzatura completa YMMV
Andy Lester,

5
Solo per controllare i @segni: /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/ jsfiddle.net/b9chris/mXB96
Chris Moschini

338

Dipende da cosa intendi meglio: se stai parlando di catturare tutti gli indirizzi email validi, usa quanto segue:

(?:(?:\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 ) Se stai cercando qualcosa di più semplice ma che catturerà la maggior parte degli indirizzi email validi, prova qualcosa del tipo:

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

EDIT: dal link:

Questa espressione regolare convaliderà solo gli indirizzi a cui sono stati rimossi commenti e sostituiti con spazi bianchi (questo viene fatto dal modulo).


10
Non corrisponde a tutti gli indirizzi, alcuni devono essere prima trasformati. Dal link: "Questa espressione regolare convaliderà solo gli indirizzi a cui sono stati rimossi commenti e sostituiti con spazi bianchi (questo viene fatto dal modulo)."
Chas. Owens,

47
Puoi darmi un esempio di alcuni email addressche attraversano erroneamente il secondo, ma vengono catturati dalla regex più lunga?
Lazer,

4
Anche se una volta l'ho adorato, è un validatore RFC 822, non uno RFC 5322 .
tchrist,

24
@Lazer in..valid @ example.com sarebbe un semplice esempio. Non è consentito avere due punti non quotati consecutivi nella parte locale.
Randal Schwartz,

5
@Mikhail perl ma non dovresti effettivamente usarlo.
Brava persona

287

[AGGIORNATO] Ho raccolto tutto ciò che so sulla convalida dell'indirizzo e-mail qui: http://isemail.info , che ora non solo convalida ma diagnostica anche i problemi con gli indirizzi e-mail. Sono d'accordo con molti dei commenti qui che la convalida è solo una parte della risposta; vedere il mio saggio su http://isemail.info/about .

is_email () rimane, per quanto ne so, l'unico validatore che ti dirà definitivamente se una determinata stringa è o meno un indirizzo email valido. Ho caricato una nuova versione su http://isemail.info/

Ho raccolto casi di test da Cal Henderson, Dave Child, Phil Haack, Doug Lovell, RFC5322 e RFC 3696. 275 indirizzi di test in tutto. Ho eseguito tutti questi test contro tutti i validatori gratuiti che ho trovato.

Cercherò di mantenere aggiornata questa pagina man mano che le persone miglioreranno i propri validatori. Grazie a Cal, Michael, Dave, Paul e Phil per il loro aiuto e cooperazione nella compilazione di questi test e critiche costruttive del mio validatore .

Le persone dovrebbero essere consapevoli delle errata in particolare contro RFC 3696 . Tre degli esempi canonici sono in realtà indirizzi non validi. E la lunghezza massima di un indirizzo è 254 o 256 caratteri, non 320.


Anche questo validatore sembra corretto. [... il tempo passa ...] Hm, sembra che sia solo RFC 5322, non 3693 o errata ad esso.
tchrist,

1
Molto bella. Qui non abbiamo solo un bel saggio, ma anche un tester di validazione e una libreria da scaricare. Bella risposta!
bgmCoder

Il tuo validatore non supporta il codice di accesso (RFC 3492). name@öäü.at può essere un indirizzo valido. (si traduce in name@xn--4ca9at.at)
Josef dice

Ciao @Josef. Dovresti provare a convalidare name@xn--4ca9at.atpoiché questo codice riguarda la convalida, non l'interpretazione. Se desideri aggiungere un traduttore punycode, sono felice di accettare una richiesta pull su github.com/dominicsayers/isemail
Dominic Sayers,

266

Secondo le specifiche HTML5 del W3C :

^[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])?)*$

Contesto:

Un indirizzo e-mail valido è una stringa che corrisponde alla produzione ABNF […].

Nota: questo requisito è una violazione intenzionale di RFC 5322 , che definisce una sintassi per gli indirizzi di posta elettronica che è contemporaneamente troppo rigida (prima del carattere "@"), troppo vaga (dopo il carattere "@") e troppo lassista ( consentendo ai commenti, ai caratteri di spazi bianchi e alle stringhe tra virgolette in maniere sconosciute alla maggior parte degli utenti) di essere qui utili.

La seguente espressione regolare compatibile con JavaScript e Perl è un'implementazione della definizione precedente.

/^[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])?)*$/


12
Questo è interessante. È una violazione di RFC, ma intenzionale e rende sesne. Esempio reale: gmail ignora i punti nella parte prima di @, quindi se la tua e-mail è test@gmail.com puoi inviare e-mail per testare. @ Gmail.com o test .... @ gmail.com, entrambi questi indirizzi sono non valido secondo RFC, ma valido nel mondo reale.
valentinas

Penso che l'ultima parte dovrebbe essere '+' invece di '*': ^ [a-zA-Z0-9.! # $% & '* + / =? ^ _ `{|} ~ -] + @ [a- zA-Z0-9 -] + (?: \. [a-zA-Z0-9 -] +) + $
mmmmmm

7
@mmmmmm john.doe@localhostè valido. Sicuramente, in un'applicazione del mondo reale (cioè una comunità), vorrei che il tuo suggerimento di sostituire * con +
rabudde,

3
@valentinas In realtà, la RFC non preclude queste parti locali, ma devono essere quotate. "test...."@gmail.comè perfettamente valido secondo la RFC e semanticamente equivalente a test....@gmail.com.
Rinke

Viene visualizzato un errore durante il tentativo di inviare e-mail utilizzando Python tramite l'inoltro della mia azienda se provo a inviare a un indirizzo con un. @ O .. @. In realtà questo è anche il caso di un _ @. Preferisco rimuovere quelli prima di inviare piuttosto che fidarmi che il destinatario lo farà.
ndvo,

201

È facile in Perl 5.10 o versioni successive:

/(?(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

20
Mi piacerebbe vederlo in Python
tdc il

4
Penso che solo un sottoinsieme della addrspecparte sia realmente rilevante per la domanda. Accettare più di questo e inoltrarlo anche se un'altra parte del sistema che non è pronta ad accettare gli indirizzi RFC5822 completi è come se sparare fosse il tuo piede.
dolmen,

3
Ottimo (+1) ma tecnicamente non è una regex ovviamente ... (il che sarebbe impossibile poiché la grammatica non è regolare).
Rinke

10
regex ha smesso di essere regolare qualche tempo fa. È un 'regex' valido Perl però!
rjh

4
Ho impostato un test per questa regex su IDEone: ideone.com/2XFecH Tuttavia, non è giusto "perfettamente". Qualcuno vorrebbe intervenire? Mi sto perdendo qualcosa?
Mike,

159

Io uso

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

Qual è quello usato in ASP.NET da RegularExpressionValidator.


28
Boo! Il mio indirizzo (sconsigliato) di !@mydomain.netè stato respinto.
Phrogz,

3
Secondo questa pagina data.iana.org/TLD/tlds-alpha-by-domain.txt non ci sono domini con un solo carattere al livello più alto, ad esempio "qualcosa.c", "qualcosa.a", ecco la versione che supporta almeno 2 caratteri: "something.pl", "something.us":^\\w+([-+.']\\w+)*@\\w+([-.]\\w+)*\\.\\w{2,}([-.]\\w+)*$
Tomasz Szulc,

4
@Wayne Whitty. Hai riscontrato il problema principale se approvare la stragrande maggioranza degli indirizzi o TUTTI, compresi quelli che nessuno userebbe, tranne che per testare la convalida della posta elettronica.
Patanjali,

La barra rovesciata extra di @TomaszSzulc nella tua risposta è confusa, l'ho appena corretta e il supporto dei nomi di domini a 2 caratteri funziona, ^ \ w + ([- +. '] \ W +) * @ \ w + ([-.] \ W +) * \. \ w {2,} ([-.] \ w +) * $
Aqib Mumtaz

2
questo fallisce su ciò simon-@hotmail.comche è in effetti valido (un nostro cliente aveva un indirizzo simile) `
Simon_Weaver,

142

Non so cosa sia meglio, ma questo è almeno corretto, purché gli indirizzi abbiano i loro commenti eliminati e sostituiti con spazi bianchi.

Sul serio. È necessario utilizzare una libreria già scritta per la convalida delle e-mail. Il modo migliore è probabilmente semplicemente inviare un'e-mail di verifica a quell'indirizzo.


2
Per quanto ne so, anche alcune biblioteche hanno torto. Ricordo vagamente che PHP PEAR aveva un tale bug.
Bortzmeyer,

In quella pagina c'è anche una dichiarazione di non responsabilità in fondo su un paio di cose dalle specifiche. che regexp non supporta.
Chris Vest,

7
Questa è una specifica RFC 822, non una specifica RFC 5322 .
tchrist

12
Alla fine, ha ragione nel dire che l'unico modo per validare veramente un indirizzo e-mail è inviargli un'e-mail e attendere una risposta.
Blazemonger,

109

Gli indirizzi e-mail che voglio convalidare verranno utilizzati da un'applicazione Web ASP.NET utilizzando lo spazio dei nomi System.Net.Mail per inviare e-mail a un elenco di persone. Quindi, piuttosto che usare un'espressione regolare molto complessa, provo solo a creare un'istanza MailAddress dall'indirizzo. Il costruttore MailAddress genererà un'eccezione se l'indirizzo non è formato correttamente. In questo modo, so che posso almeno ottenere l'e-mail fuori dalla porta. Ovviamente si tratta di una convalida sul lato server, ma almeno è necessaria.

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

3
Un buon punto Anche se questa convalida del server rifiuta un indirizzo valido, non è un problema poiché non sarà comunque possibile inviare a questo indirizzo utilizzando questa particolare tecnologia server. Oppure puoi provare a fare le stesse cose usando qualsiasi libreria di e-mail di terze parti che usi al posto degli strumenti predefiniti.
Utente

Mi piace molto il modo in cui questo sfrutta il codice framework .Net - non ha senso reinventare la ruota. Questo è eccellente Semplice, pulito e garantisce che puoi effettivamente inviare l'e-mail. Ottimo lavoro.
Cory House,

... sì e per chi è interessato a come si convalida dai un'occhiata al codice in Reflector - ce n'è un bel po '- e non è un'espressione regolare!
Tom Carter,

2
Solo una nota: la classe MailAddress non corrisponde a RFC5322, se si desidera utilizzarlo solo per la convalida (e non anche l'invio, nel qual caso si tratta di un punto controverso come menzionato sopra). Vedere: stackoverflow.com/questions/6023589/...
Porges

Solo un piccolo problema: se vuoi rendere più riutilizzabile il tuo codice validatore lato server (in questo caso o in generale), ti suggerisco di usare args.Valueinvece di fare riferimento al campo come txtEmail.Texthardcoded. Quest'ultimo vincolerà il tuo validatore alla singola istanza di controllo, che potrebbe essere OK, a condizione che tu abbia un singolo campo e-mail, ma non è raccomandato diversamente.
pholpar il

109

Risposta rapida

Utilizzare la seguente regex per la convalida dell'input:

([-!#-'*+/-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])?)+

Indirizzi corrispondenti a questa regex:

  • avere una parte locale (cioè la parte prima del segno @) che sia rigorosamente conforme a RFC 5321/5322,
  • hanno una parte di dominio (ovvero la parte dopo il segno @) che è un nome host con almeno due etichette, ognuna delle quali è lunga al massimo 63 caratteri.

Il secondo vincolo è una limitazione di RFC 5321/5322.

Risposta elaborata

L'uso di un'espressione regolare che riconosce gli indirizzi e-mail potrebbe essere utile in varie situazioni: ad esempio per cercare gli indirizzi e-mail in un documento, convalidare l'input dell'utente o come vincolo di integrità in un repository di dati.

Va tuttavia notato che se si desidera scoprire se l'indirizzo si riferisce effettivamente a una cassetta postale esistente, non vi è alcun sostituto per l'invio di un messaggio all'indirizzo. Se vuoi solo verificare se un indirizzo è grammaticalmente corretto, puoi usare un'espressione regolare, ma nota che ""@[]è un indirizzo email grammaticalmente corretto che certamente non si riferisce a una casella di posta esistente.

La sintassi degli indirizzi e-mail è stata definita in vari RFC , in particolare RFC 822 e RFC 5322 . RFC 822 dovrebbe essere visto come lo standard "originale" e RFC 5322 come lo standard più recente. La sintassi definita in RFC 822 è la più delicata e gli standard successivi hanno limitato ulteriormente la sintassi, in cui i sistemi o i servizi più recenti dovrebbero riconoscere la sintassi obsoleta, ma non produrla mai.

In questa risposta prenderò "indirizzo e-mail" nel senso addr-specdefinito nelle RFC (ovvero jdoe@example.org, ma non "John Doe"<jdoe@example.org>, né some-group:jdoe@example.org,mrx@exampel.org;).

C'è un problema con la traduzione delle sintassi RFC in regex: le sintassi non sono regolari! Questo perché consentono commenti facoltativi negli indirizzi e-mail che possono essere nidificati all'infinito, mentre la nidificazione infinita non può essere descritta da un'espressione regolare. Per cercare o validare indirizzi contenenti commenti è necessario un parser o espressioni più potenti. (Nota che linguaggi come il Perl hanno costrutti per descrivere grammatiche libere dal contesto in modo simile alla regex.) In questa risposta ignorerò i commenti e prenderò in considerazione solo le espressioni regolari appropriate.

Gli RFC definiscono le sintassi per i messaggi e-mail, non per gli indirizzi e-mail in quanto tali. Gli indirizzi possono apparire in vari campi di intestazione ed è qui che sono principalmente definiti. Quando compaiono nei campi dell'intestazione, gli indirizzi possono contenere (tra token lessicali) spazi bianchi, commenti e persino interruzioni di riga. Semanticamente questo non ha significato. Rimuovendo questo spazio bianco, ecc. Da un indirizzo si ottiene una rappresentazione canonica semanticamente equivalente . Pertanto, la rappresentazione canonica di first. last (comment) @ [3.5.7.9]è first.last@[3.5.7.9].

Sintassi diverse devono essere utilizzate per scopi diversi. Se si desidera cercare gli indirizzi e-mail in un documento (forse molto vecchio), potrebbe essere una buona idea utilizzare la sintassi come definita in RFC 822. D'altra parte, se si desidera convalidare l'input dell'utente, è possibile utilizzare sintassi come definita in RFC 5322, probabilmente accettando solo rappresentazioni canoniche. Dovresti decidere quale sintassi si applica al tuo caso specifico.

In questa risposta uso espressioni regolari "estese" POSIX, assumendo un set di caratteri compatibile ASCII.

RFC 822

Sono arrivato alla seguente espressione regolare. Invito tutti a provare a romperlo. Se trovi falsi positivi o falsi negativi, ti preghiamo di pubblicarli in un commento e cercherò di correggere l'espressione il prima possibile.

([^][()<>@,;:\\". \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)*]))*

Credo che sia pienamente compatibile con RFC 822 compresi gli errata . Riconosce solo gli indirizzi e-mail nella loro forma canonica. Per una regex che riconosce gli spazi bianchi (pieghevoli) vedere la derivazione di seguito.

La derivazione mostra come sono arrivato all'espressione. Elenco tutte le regole grammaticali rilevanti dall'RFC esattamente come appaiono, seguite dalla regex corrispondente. Laddove è stato pubblicato un errore, do un'espressione separata per la regola grammaticale corretta (contrassegnata "erratum") e uso la versione aggiornata come sottoespressione nelle successive espressioni regolari.

Come indicato al paragrafo 3.1.4. dello spazio bianco lineare opzionale RFC 822 può essere inserito tra i token lessicali. Laddove applicabile, ho ampliato le espressioni per soddisfare questa regola e contrassegnato il risultato con "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

Sono arrivato alla seguente espressione regolare. Invito tutti a provare a romperlo. Se trovi falsi positivi o falsi negativi, ti preghiamo di pubblicarli in un commento e cercherò di correggere l'espressione il prima possibile.

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

Credo che sia pienamente compatibile con RFC 5322 compresi gli errata . Riconosce solo gli indirizzi e-mail nella loro forma canonica. Per una regex che riconosce gli spazi bianchi (pieghevoli) vedere la derivazione di seguito.

La derivazione mostra come sono arrivato all'espressione. Elenco tutte le regole grammaticali rilevanti dall'RFC esattamente come appaiono, seguite dalla regex corrispondente. Per le regole che includono spazi bianchi (pieghevoli) semanticamente irrilevanti, do una regex separata contrassegnata "(normalizzata)" che non accetta questo spazio bianco.

Ho ignorato tutte le regole "obs-" dalla RFC. Ciò significa che le regex corrispondono solo a indirizzi e-mail rigorosamente conformi a RFC 5322. Se devi abbinare indirizzi "vecchi" (come fa la grammatica più libera, comprese le regole "obs-"), puoi usare una delle regex RFC 822 del paragrafo precedente.

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

Si noti che alcune fonti (in particolare w3c ) affermano che RFC 5322 è troppo severo sulla parte locale (cioè la parte prima del segno @). Questo perché "..", "a..b" e "a." non sono dot-atomi validi, mentre possono essere usati come nomi di cassette postali. Il RFC, tuttavia, non consentono di parti locali come questi, se non che essi devono essere citato. Quindi, invece di a..b@example.nette, dovresti scrivere "a..b"@example.net, che è semanticamente equivalente.

Ulteriori restrizioni

SMTP (come definito in RFC 5321 ) limita ulteriormente l'insieme di indirizzi e-mail validi (o effettivamente: nomi di cassette postali). Sembra ragionevole imporre questa grammatica più rigorosa, in modo che l'indirizzo di posta elettronica abbinato possa effettivamente essere utilizzato per inviare un'e-mail.

RFC 5321 praticamente lascia da solo la parte "locale" (cioè la parte prima del segno @), ma è più rigorosa sulla parte del dominio (cioè la parte dopo il segno @). Permette solo nomi host al posto di dot-atomi e letterali di indirizzi al posto di letterali di dominio.

La grammatica presentata in RFC 5321 è troppo indulgente quando si tratta di nomi host e indirizzi IP. Mi sono preso la libertà di "correggere" le regole in questione, usando questa bozza e RFC 1034 come linee guida. Ecco la regex risultante.

([-!#-'*+/-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^-~]+)])

Nota che, a seconda del caso d'uso, potresti non voler consentire un "indirizzo generale-letterale" nel tuo regex. Nota anche che ho usato un lookahead negativo (?!IPv6:)nella regex finale per evitare che la parte "Indirizzo generale-letterale" corrispondesse agli indirizzi IPv6 non validi. Alcuni processori regex non supportano lookahead negativo. Rimuovere la sottostringa |(?!IPv6:)[0-9A-Za-z-]*[0-9A-Za-z]:[!-Z^-~]+dalla regex se si desidera eliminare l'intera parte "Indirizzo generale-letterale".

Ecco la derivazione:

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

Convalida dell'input dell'utente

Un caso d'uso comune è la convalida dell'input dell'utente, ad esempio in un modulo HTML. In tal caso, di solito è ragionevole escludere i letterali degli indirizzi e richiedere almeno due etichette nel nome host. Prendendo come base la regex RFC 5321 migliorata della sezione precedente, l'espressione risultante sarebbe:

([-!#-'*+/-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])?)+

Non consiglio di limitare ulteriormente la parte locale, ad esempio precludendo le stringhe tra virgolette, poiché non sappiamo quale tipo di nomi di cassette postali alcuni host consentono (come "a..b"@example.neto addirittura "a b"@example.net).

Inoltre, non consiglio di convalidare esplicitamente un elenco di domini letterali di primo livello o addirittura di imporre vincoli di lunghezza (ricorda come ".museum" invalidato [a-z]{2,4}), ma se devi:

([-!#-'*+/-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|eccetera...)

Assicurati di mantenere aggiornato regex se decidi di seguire il percorso della convalida esplicita del dominio di primo livello.

Ulteriori considerazioni

Quando si accettano solo nomi host nella parte del dominio (dopo il segno @), le regex sopra accettano solo etichette con al massimo 63 caratteri, come dovrebbero. Tuttavia, non impongono il fatto che l'intero nome host deve essere lungo al massimo 253 caratteri (inclusi i punti). Sebbene questo vincolo sia ancora rigorosamente regolare, non è possibile creare una regex che incorpori questa regola.

Un'altra considerazione, specialmente quando si usano le regex per la validazione dell'input, è il feedback all'utente. Se un utente immette un indirizzo errato, sarebbe bello dare un po 'più di feedback di un semplice "indirizzo sintatticamente errato". Con regex "vaniglia" questo non è possibile.

Queste due considerazioni potrebbero essere risolte analizzando l'indirizzo. Il vincolo di lunghezza extra sui nomi host potrebbe anche essere risolto in alcuni casi utilizzando una regex aggiuntiva che lo controlla e abbinando l'indirizzo a entrambe le espressioni.

Nessuno dei regex in questa risposta è ottimizzato per le prestazioni. Se le prestazioni sono un problema, dovresti vedere se (e come) la regex di tua scelta può essere ottimizzata.


3
RFC 6532 aggiorna 5322 per consentire e includere UTF-8 completo e pulito. Ulteriori dettagli qui .

Secondo Wikipedia sembra che la parte locale, una volta punteggiata, abbia una limitazione di 64 caratteri per parte, e anche l'RFC 5322 si riferisce alla parte locale punteggiata da interpretare con le restrizioni dei domini. Ad esempio arbitrary-long-email-address-should-be-invalid-arbitrary-long-email-address-should-be-invalid.and-the-second-group-also-should-not-be-so-long-and-the-second-group-also-should-not-be-so-long@example.com, non è necessario convalidare. Suggerisco di cambiare i segni "+" nel primo gruppo (nome prima del punto facoltativo) e nel secondo gruppo (nome dopo i punti seguenti) in{1,64}
Xavi Montero,

Poiché i commenti hanno dimensioni limitate, ecco la regex risultante che intendo utilizzare, che è quella all'inizio di questa risposta, oltre a limitare le dimensioni nella parte locale, oltre ad aggiungere una barra rovesciata prima del "/" simbolo come richiesto da PHP e anche in regex101.com: In PHP uso:$emailRegex = '/^([-!#-\'*+\/-9=?A-Z^-~]{1,64}(\.[-!#-\'*+\/-9=?A-Z^-~]{1,64})*|"([]!#-[^-~ \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])?)+$/';
Xavi Montero,

ATTENZIONE: per qualche motivo, StackOverflow aggiunge caratteri nascosti quando si copia dal markdown renderizzato. Copialo su regex101.com e vedrai dei punti neri lì. Devi rimuoverli e correggere la stringa ... Forse se integrati nella risposta, lì sono correttamente copiabili. Ci dispiace per l'inconvenienza. Non voglio aggiungere una nuova risposta poiché questa è quella giusta. Inoltre, non voglio modificare direttamente se la comunità non pensa che questo debba essere integrato in esso.
Xavi Montero,

@XaviMontero Thaks per aver contribuito con Xavi! Avete un riferimento all'RFC che indica il limite di 64 caratteri sulle etichette locali delle parti? In tal caso, adeguerei volentieri la risposta.
Rinke

73

Ci sono molti esempi di questo in rete (e penso che anche uno che convalidi completamente l'RFC - ma sono lunghe decine / centinaia di righe se la memoria serve). Le persone tendono a lasciarsi trasportare convalidando questo genere di cose. Perché non solo controllare che abbia un @ e almeno uno. e incontra una semplice lunghezza minima. È banale inserire un'e-mail falsa e comunque uguagliare qualsiasi regex valida. Immagino che i falsi positivi siano migliori dei falsi negativi.


1
Sì, ma quale RFC? :) Questo [validatore RFC-5322] ( stackoverflow.com/questions/201323/… ) è lungo solo una quarantina di righe.
tchrist

14
A. non è richiesto. Un TLD può avere indirizzi e-mail o potrebbe esserci un indirizzo IPv6
Sijmen Mulder,

1
Le RFC non sono la fine della storia: l'ICANN non consente più domini "senza punti": icann.org/news/announcement-2013-08-30-it
Synchro

64

Mentre decidi quali personaggi sono ammessi, ricorda i tuoi amici apostrofi e sillabati. Non ho alcun controllo sul fatto che la mia azienda generi il mio indirizzo e-mail usando il mio nome dal sistema delle risorse umane. Ciò include l'apostrofo nel mio cognome. Non posso dirti quante volte mi è stato impedito di interagire con un sito Web dal fatto che il mio indirizzo e-mail è "non valido".


4
Questo è un problema super comune nei programmi che fanno ipotesi ingiustificate su ciò che è e non è permesso a nome di una persona. Non si dovrebbero fare ipotesi del genere, basta accettare qualsiasi carattere che le RFC pertinenti dichiarino di dover fare.
tchrist

4
Sì. Sono particolarmente infuriato contro i programmatori che rifiutano le lettere maiuscole negli indirizzi e-mail! Sciocco e / o pigro.
PhiLho,

63

Questa regex proviene dalla libreria Email :: Valid di Perl . Credo che sia il più preciso, corrisponde a tutti gli 822. E, si basa sull'espressione regolare nel libro di O'Reilly:

Espressione regolare creata usando l'esempio di Jeffrey Friedl in Mastering Regular Expressions ( http://www.ora.com/catalog/regexp/ ).

$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

14
O_O dovresti anche essere un maestro regex per capire cosa sta facendo
Chris McGrath,

45

Mentre scrivi in ​​PHP ti consiglio di usare la validazione integrata di PHP per le e-mail.

filter_var($value, FILTER_VALIDATE_EMAIL)

Se stai utilizzando una versione php precedente alla 5.3.6, tieni presente questo problema: https://bugs.php.net/bug.php?id=53091

Se vuoi maggiori informazioni su come funziona questa validazione integrata , vedi qui: Filter_var FILTER_VALIDATE_EMAIL di PHP funziona davvero?


ottiene un voto, esattamente quello che stavo per dire. Non gestisce gli IDN ma la conversione in codice errato in anticipo risolve questo problema. PHP> = 5.3 ha idn_to_ascii () per questo. Uno dei modi migliori e più semplici per convalidare un'e-mail.
Taylor,


42

Non mi preoccupo mai di creare con la mia espressione regolare, perché è probabile che qualcun altro abbia già trovato una versione migliore. Uso sempre regexlib per trovarne uno di mio gradimento.


1
Questo è stato segnalato per lunghezza e contenuto, ma è comunque un buon contributo con 41 voti e non deve essere eliminato.
Sarà il

37

Non ce n'è uno che sia realmente utilizzabile.
Discuto alcuni problemi nella mia risposta a Esiste una libreria php per la convalida dell'indirizzo e-mail? , è discusso anche nel riconoscimento Regexp dell'indirizzo e-mail duro?

In breve, non aspettatevi che una sola regex utilizzabile faccia un lavoro adeguato. E la regex migliore convaliderà la sintassi, non la validità di un'e-mail (jhohn@example.com è corretta ma probabilmente rimbalzerà ...).


Correggimi se sbaglio, ma credo che PHP usi modelli PCRE. In tal caso, dovresti essere in grado di creare qualcosa di simile al modello RFC 5322 di Abigail .
tchrist

@tchrist: non sono sicuro che PCRE abbia raggiunto questa sintassi (che scopro). Se è così, non sono sicuro che il PCRE di PHP abbia raggiunto questa versione di PCRE ... Beh, se capisco correttamente questa sintassi, puoi anche usare un parser PEG, molto più chiaro e completo di una regex.
PhiLho,

PCRE l' ha raggiunto, ma forse PHP non ha raggiunto PCRE. ☹
tchrist

36

Una semplice espressione regolare che almeno non respingerebbe un indirizzo email valido sarebbe la ricerca di qualcosa, seguita da un segno @ e poi qualcosa seguito da un punto e almeno 2 qualcosa. Non rifiuterà nulla, ma dopo aver esaminato le specifiche non riesco a trovare alcuna email valida e rifiutata.

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


3
Questo è quello che stavo cercando. Non molto restrittivo, ma assicurati che ci sia solo 1 @ (poiché stiamo analizzando un elenco e vogliamo assicurarci che non ci siano virgole mancanti). Cordiali saluti, puoi avere un @ a sinistra se è tra virgolette: Valid_email_addresses , ma è piuttosto marginale.
Josh,

2
Dopo averlo usato, ho capito che non funzionava esattamente. /^[^@]+@[^@]+\.[^@]{2}[^@]*$/ controlla effettivamente 1 @ sign. Il tuo regex lascerà passare molti a causa del. * Alla fine.
Josh,

1
Giusto. Non sto cercando di rifiutare tutto ciò che non è valido, mi limito a rifiutare un indirizzo email valido.
spig

1
Sarebbe molto meglio usarlo: /^[^@]+@[^@]+\.[^@]{2,4}$/assicurarsi che finisca con 2-4 caratteri non @. Come ha sottolineato @Josh, ora consente un extra @ alla fine. Ma puoi anche cambiarlo in: /^[^@]+@[^@]+\.[^a-z-A-Z]{2,4}$/poiché tutti i domini di primo livello sono aZ. puoi sostituire il 4con 5o più consentendo anche ai nomi di dominio di livello superiore di essere più lunghi in futuro.
VOLA il

@FLY, ka @ foo. ritorna corretto. Dovrebbe, secondo gli standard?
SexyBeast,

29

È possibile utilizzare quello utilizzato dal plug-in di convalida 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

sembra che stia facendo un buon lavoro. Ha permesso: a-b'c_d.e@f-g.hma è stato in grado di cogliere le variazioni inadeguate, come a-b'c_d.@f-g.hea-b'c_d.e@f-.h
dsdsdsdsd

25

Per la valutazione più completa della migliore espressione regolare per la convalida di un indirizzo e-mail, consultare questo link; " Confronto dell'indirizzo e-mail che convalida le espressioni regolari "

Ecco l'espressione superiore corrente a scopo di riferimento:

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

spoon16: Quel link non è proprio corretto. La sua affermazione che non può esserci un modello perfetto per la convalida degli indirizzi e-mail è palesemente un errore. È possibile , ma bisogna fare in modo che si segue la RFC fino alla lettera. E devi scegliere anche la RFC giusta.
tchrist,

Il "migliore" in questo momento non funziona con java regex - anche dopo aver correttamente evaso e convertito la stringa.
Eric Chen,

23

Per non parlare del fatto che i nomi di dominio non latini (cinese, arabo, greco, ebraico, cirillico e così via) saranno autorizzati nel prossimo futuro . Ognuno deve cambiare la regex di posta elettronica utilizzata, poiché quei personaggi sicuramente non saranno coperti da [a-z]/i\w. Falliranno tutti.

Dopotutto, il modo migliore per convalidare l'indirizzo e-mail è comunque quello di inviare un'e-mail all'indirizzo in questione per convalidare l'indirizzo. Se l'indirizzo e-mail fa parte dell'autenticazione utente (registrati / accedi / ecc.), Puoi combinarlo perfettamente con il sistema di attivazione dell'utente. Vale a dire inviare un'e-mail con un collegamento con una chiave di attivazione univoca all'indirizzo e-mail specificato e consentire l'accesso solo quando l'utente ha attivato l'account appena creato utilizzando il collegamento nell'e-mail.

Se lo scopo di regex è solo quello di informare rapidamente l'utente nell'interfaccia utente che l'indirizzo e-mail specificato non ha l'aspetto nel formato corretto, è comunque meglio verificare se corrisponde sostanzialmente al seguente regex:

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

Semplice come quella. Perché mai ti interesseresti dei personaggi usati nel nome e nel dominio? È responsabilità del cliente inserire un indirizzo e-mail valido, non quello del server. Anche quando il client inserisce un indirizzo email sintatticamente valido come aa@bb.ccquesto, ciò non garantisce che sia un indirizzo email legittimo. Nessuno regex può coprirlo.


4
Sono d'accordo che l'invio di un messaggio di autenticazione è di solito il modo migliore per questo tipo di cose, sintatticamente corrette e valide non sono le stesse. Mi sento frustrato quando mi viene chiesto di digitare due volte il mio indirizzo e-mail per "Conferma" come se non riuscissi a vedere ciò che ho digitato. Copio solo il primo al secondo, sembra che venga utilizzato sempre di più.
PeteT,

essere d'accordo! ma questa regex non credo sia valida perché permette spacesdopo l' @.es. test@test.ca com netè considerato un indirizzo e-mail valido utilizzando la regex sopra dove come dovrebbe essere restituito non valido.
CB4,

20

Le specifiche HTML5 suggeriscono una semplice regex per la convalida degli indirizzi e-mail:

/^[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])?)*$/

Questo non è intenzionalmente conforme a RFC 5322 .

Nota: questo requisito è una violazione intenzionale di RFC 5322 , che definisce una sintassi per gli indirizzi di posta elettronica che è contemporaneamente troppo rigida (prima del @carattere), troppo vaga (dopo il @carattere) e troppo lassista (consentendo commenti, caratteri di spazi bianchi, e ha citato stringhe in maniere non familiari alla maggior parte degli utenti) per essere utili qui.

La lunghezza totale potrebbe anche essere limitata a 254 caratteri, per RFC 3696 errata 1690 .


Migliore risposta! Ecco un link alla raccomandazione w3: w3.org/TR/html5/forms.html#valid-e-mail-address Questo regex è adottato da molti browser.
Ryan Taylor,

3
Questa non è quindi la risposta migliore! Questo modello corrisponde a questo indirizzo del tutto valido: invalid@emailaddress. Inviterei cautela e molti test prima di utilizzarlo!
Sheridan,

@Sheridan, se pensi che ci sia un problema con le specifiche HTML5 puoi sollevare un problema qui: github.com/w3c/html/issues
Luna

Questo non aggiunge molto su stackoverflow.com/a/8829363 e IMHO sarebbe meglio se modificarlo o commentarlo.

esempio @ localhost è valido, ma per un'applicazione del mondo reale potresti voler applicare un'estensione di dominio, tutto ciò che devi fare è cambiare l'ultimo * in un + per raggiungere questo obiettivo (cambiando quella parte del modello da 0+ a 1+ )
Mitch Satchwell,

15

Per una vivida dimostrazione, il seguente mostro è piuttosto buono ma non riconosce ancora correttamente tutti gli indirizzi e-mail sintatticamente validi: riconosce i commenti nidificati fino a quattro livelli di profondità.

Questo è un lavoro per un parser, ma anche se un indirizzo è sintatticamente valido, potrebbe non essere ancora disponibile. A volte devi ricorrere al metodo hillbilly di "Ehi, tutti, guardate ee-us!"

// 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); 

12

Secondo lo standard ufficiale RFC 2822, regex email valido è

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

se vuoi usarlo in Java è davvero molto semplice

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

1
Il tuo regex non include la prima lettera maiuscola, ad esempio Leonardo.davinci@gmail.com, che potrebbe essere fastidiosa per alcuni utenti. Usa questo invece:(?:[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-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])+)\])
Kebab Krabby

@KebabKrabby Grazie, modifica la risposta, accetterò la modifica.
AZ_31

Se aggiungo quella modifica alla tua risposta, non sarà più RFC 2822, quindi non so se sia corretto.
Kebab Krabby,

11

Ecco il PHP che uso. Ho scelto questa soluzione nello spirito di "i falsi positivi sono migliori dei falsi negativi" come dichiarato da un altro commentatore qui E per quanto riguarda il mantenimento dei tempi di risposta e il caricamento del server ... non c'è davvero bisogno di sprecare risorse del server con un'espressione regolare quando eliminerà il più semplice errore dell'utente. Puoi sempre seguirlo inviando un'email di prova, se lo desideri.

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

1
a) Le "risorse del server dei rifiuti" sono infinitesime, ma se sei così incline, potresti farlo lato client con JS b) Di cosa hai bisogno per inviare una mail di registrazione e l'utente mi inserisce @ forgotthedotcom? La tua "soluzione" fallisce e perdi un utente.
johnjohn,


11

Standard RFC 5322:

Permette dominio locale parte-atomo, parte locale di stringa tra virgolette, parte locale obsoleta (punto di atomi misti e stringa tra virgolette), dominio nome dominio, dominio IPv6 (indirizzo IPv4, IPv6 e IPv4 mappato IPv4), e (nidificati) 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'

Standard RFC 5321:

Consente il dominio letterale punto-atomo locale, stringa locale tra virgolette, dominio nome dominio e dominio IPv6 (indirizzo IPv4, IPv6 e IPv4 mappato IPv4).

'/^(?!(?>"?(?>\\\[ -~]|[^"])"?){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'

Di base:

Permette il dominio della parte locale e del nome di dominio dot-atom (che richiede almeno due etichette di nomi di dominio con TLD limitato a 2-6 caratteri alfabetici).

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

Qual è la lingua del diavolo in ?? Vedo una /Dbandiera e l'hai citata con virgolette singole ma hai anche usato le barre per delimitare il modello? Non è Perl e non può essere PCRE. È quindi PHP? Credo che questi siano gli unici tre che consentono la ricorsione come (?1).
tchrist,

È in PHP, che utilizza PCRE. Le barre vengono utilizzate solo per delimitare caratteri speciali come parentesi, parentesi quadre e, naturalmente, barre e virgolette singole. Il flag / D, se non lo sapevi, impedisce che una nuova riga venga aggiunta alla fine della stringa, che sarebbe altrimenti consentita.
MichaelRushton,

9

Strano che non sia possibile "consentire" TLD a 4 caratteri. Stai vietando le persone da .info e .name e la limitazione della lunghezza ferma .travel e .museum , ma sì, sono meno comuni di TLD a 2 caratteri e TLD a 3 caratteri.

Dovresti consentire anche alfabeti maiuscoli. I sistemi di posta elettronica normalizzeranno la parte locale e la parte del dominio.

Per la tua regex della parte di dominio, il nome di dominio non può iniziare con '-' e non può terminare con '-'. Dash può rimanere solo in mezzo.

Se hai utilizzato la libreria PEAR, controlla la loro funzione di posta (hai dimenticato il nome / la libreria esatti). È possibile convalidare l'indirizzo e-mail chiamando una funzione e convalida l'indirizzo e-mail in base alla definizione in RFC822.


2
@Joseph Yee: RFC 822 non è un po 'datato?
tchrist,

8
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;
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.