¿Cuál es el mejor método de validación de dirección de correo electrónico de Java? [cerrado]

247

¿Cuáles son las buenas bibliotecas de validación de direcciones de correo electrónico para Java? ¿Hay alguna alternativa al validador de bienes comunes ?

jon077
fuente
15
Voy a dejar esto aquí: davidcelis.com/blog/2012/09/06/…
mpenkov
44
URL actual para Commons: commons.apache.org/proper/commons-validator/apidocs/org/apache/…
james.garriss
No debería querer usar bibliotecas (o expresiones regulares) que no validen de manera exhaustiva. Debido a la complejidad de una dirección de correo electrónico válida, no existe un punto medio entre la no validación y la validación integral. La implementación de Apache Commons no es exhaustiva. Soy consciente de que solo hay una biblioteca ( email-rfc2822-validator ), pero aún funciona con grandes expresiones regulares. Un lexer integral es lo que realmente quieres. EmailValidator4J dice que hace el trabajo, pero no tengo experiencia con eso.
Benny Bottema
1
@BennyBottema En lugar de editar la pregunta con comentarios, haga una publicación Meta para discutir por qué esto se cerró si aún tiene preguntas.
Machavity

Respuestas:

134

Apache Commons es generalmente conocido como un proyecto sólido. Sin embargo, tenga en cuenta que aún tendrá que enviar un correo electrónico de verificación a la dirección si desea asegurarse de que sea un correo electrónico real y que el propietario quiera que se use en su sitio.

EDITAR : Hubo un error donde era demasiado restrictivo en el dominio, lo que hacía que no aceptara correos electrónicos válidos de nuevos TLD.

Este error se resolvió el 03 / Jan / 15 02:48 en commons-validator versión 1.4.1

Matthew Flaschen
fuente
1
Estoy de acuerdo con los bits adicionales que citó, pero ¿son parte del proyecto de Validación de Commons?
duffymo
2
No, la EmailValidatorclase Apache no envía un mensaje de correo electrónico para su verificación.
Matthew Flaschen
3
Si su caso de uso es validar la dirección de correo electrónico remota de un usuario, esta solución tiene un defecto considerable (similar a InternetAddress.validate ()): EmailValidator considera al usuario @ [10.9.8.7] como direcciones de correo electrónico válidas, que están de acuerdo con RFC, pero tal vez no para el registro de usuario / formulario de contacto.
zillion1
1
@zillion, que está documentado en Apache COmmons: "No se garantiza que esta implementación detecte todos los errores posibles en una dirección de correo electrónico". Y dije lo que tienes que hacer para "asegurarte de que sea un correo electrónico real". Sin embargo, las direcciones con IP locales podrían ser válidas en entornos raros.
Matthew Flaschen
55
Apache Commons EmailValidator tiene un serio inconveniente: no admite IDN.
Piohen
261

Usar el paquete oficial de correo electrónico de Java es lo más fácil:

public static boolean isValidEmailAddress(String email) {
   boolean result = true;
   try {
      InternetAddress emailAddr = new InternetAddress(email);
      emailAddr.validate();
   } catch (AddressException ex) {
      result = false;
   }
   return result;
}
Aaron Davidson
fuente
59
Tenga en cuenta que InternetAddress.validate () considera al usuario @ [10.9.8.7] y al usuario @ localhost como direcciones de correo electrónico válidas, que son de acuerdo con la RFC. Sin embargo, dependiendo del caso de uso (formulario web), es posible que desee tratarlos como no válidos.
zillion1
8
no solo eso es válido como dijo @ zillion1, sino que también cosas como bla @ bla se consideran válidas. Realmente no es la mejor solución.
Diego Plentz
44
@NicholasTolleyCottrell Esto es Java, aquí lanzamos y atrapamos excepciones, realmente no entiendo tu punto
gyorgyabraham
17
Sospecho que el constructor de InternetAddress ha sido manipulado. O mi sistema ha sido manipulado. O RFC822 ha sido manipulado. O realmente podría usar un poco de sueño en este momento. Pero acabo de probar un código y las siguientes cinco cadenas pasan todas como direcciones de correo electrónico válidas si las pasa al constructor de InternetAddress, y "claramente", no son válidas. Aquí vamos: ., .com, com., abcy 123. Además, agregar espacios en blanco iniciales o finales tampoco invalida las cadenas. ¡Se el juez!
Martin Andersson
44
um, el queso falla correctamente cuando lo ejecuto. ¿a qué demonios está enlazando la biblioteca javax.mail?
Aaron Davidson
91

El validador de Apache Commons se puede usar como se menciona en las otras respuestas.

pom.xml:

<dependency>
    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.4.1</version>
</dependency>

build.gradle:

compile 'commons-validator:commons-validator:1.4.1'

La importación:

import org.apache.commons.validator.routines.EmailValidator;

El código:

String email = "[email protected]";
boolean valid = EmailValidator.getInstance().isValid(email);

y para permitir direcciones locales

boolean allowLocal = true;
boolean valid = EmailValidator.getInstance(allowLocal).isValid(email);
Aksel Willgert
fuente
2
En Android Studio puede agregar la compilación 'commons-validator: commons-validator: 1.4.1' en las dependencias de su aplicación \ build.gradle {}
Benjiko99
2
Después de tratar de construir mi proyecto, parece que apache commons no funciona muy bien con Android, cientos de advertencias y algunos errores, ni siquiera se compila. Esto es lo que terminé usando howtodoinjava.com/2014/11/11/java-regex-validate-email-address
Benjiko99
1
El mismo problema conmigo que con Benjiko99. Después de agregar la dependencia, el proyecto no se compilará, dice que java.exe finalizó con un código de salida distinto de cero 2.
Amit Mittal
1
También recibí errores en Android Studio. ¡Cambié de 1.4.1 a 1.5.1 y funciona!
Matt
1
Nota: Use_the Emailvalidator en org.apache.commons.validator.routines ya que EmailValidator en org.apache.commons.validator está en desuso (estoy usando 1.6 commons Validator)
HopeKing
71

Respuesta tardía, pero creo que es simple y digno:

    public boolean isValidEmailAddress(String email) {
           String ePattern = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$";
           java.util.regex.Pattern p = java.util.regex.Pattern.compile(ePattern);
           java.util.regex.Matcher m = p.matcher(email);
           return m.matches();
    }

Casos de prueba :

ingrese la descripción de la imagen aquí

Para fines de producción, las validaciones de nombres de dominio deben realizarse en red.

Pujan Srivastava
fuente
40
Es un validador bastante brutalmente simplista que ignora la mayoría de las reglas de RFC junto con los IDN. Me mantendría alejado de esto para cualquier aplicación de calidad de producción.
mlaccetti
1
[email protected] no será válido ...
Alexander Burakevych
14
No utilice su propio validador basado en expresiones regulares para cosas cubiertas por RFC.
Josh Glover
66
reinventar la rueda está bien siempre y cuando no le
importe
es bueno pero no para todos los casos.
Andrain
21

Si está intentando hacer una validación de formulario recibida del cliente, o simplemente una validación de bean, que sea simple. Es mejor hacer una validación de correo electrónico flexible en lugar de hacer una estricta y rechazar a algunas personas (por ejemplo, cuando intentan registrarse en su servicio web). Con casi todo lo permitido en la parte del nombre de usuario del correo electrónico y tantos dominios nuevos que se agregan literalmente cada mes (por ejemplo, .company, .entreprise, .estate), es más seguro no ser restrictivo:

Pattern pattern = Pattern.compile("^.+@.+\\..+$");
Matcher matcher = pattern.matcher(email);
Alexander Burakevych
fuente
3
Este es un muy buen punto, cualquier aplicación razonable debería tener otras medidas para prevenir esta entrada de la explotación en la línea de todos modos
jmaculate
44
¿Qué tal cambiarlo a "^. + @. + (\\. [^ \\.] +) + $" Para evitar un punto final?
Xingang Huang
7

Tarde a la pregunta, aquí, pero: mantengo una clase en esta dirección: http://lacinato.com/cm/software/emailrelated/emailaddress

Se basa en la clase de Les Hazlewood, pero tiene numerosas mejoras y corrige algunos errores. Licencia de Apache.

Creo que es el analizador de correo electrónico más capaz en Java, y todavía tengo que ver uno más capaz en cualquier idioma, aunque puede haber uno por ahí. No es un analizador de estilo lexer, pero utiliza algunas expresiones regulares de Java complicadas y, por lo tanto, no es tan eficiente como podría ser, pero mi compañía ha analizado más de 10 mil millones de direcciones del mundo real con él: ciertamente es utilizable en un alto rendimiento situación. Tal vez una vez al año llegue a una dirección que cause un desbordamiento de la pila de expresiones regulares (apropiadamente), pero estas son direcciones de correo no deseado que tienen cientos o miles de caracteres de largo con muchas comillas y paréntesis y similares.

RFC 2822 y las especificaciones relacionadas son realmente bastante permisivas en términos de direcciones de correo electrónico, por lo que una clase como esta es excesiva para la mayoría de los usos. Por ejemplo, la siguiente es una dirección legítima, de acuerdo con las especificaciones, espacios y todo:

"<bob \" (here) " < (hi there) "bob(the man)smith" (hi) @ (there) example.com (hello) > (again)

Ningún servidor de correo permitiría eso, pero esta clase puede analizarlo (y reescribirlo en un formulario utilizable).

Descubrimos que las opciones existentes del analizador de correo electrónico Java son insuficientemente duraderas (lo que significa que no todas pudieron analizar algunas direcciones válidas), por lo que creamos esta clase.

El código está bien documentado y tiene muchas opciones fáciles de cambiar para permitir o rechazar ciertos formularios de correo electrónico. También proporciona muchos métodos para acceder a ciertas partes de la dirección (lado izquierdo, lado derecho, nombres personales, comentarios, etc.), para analizar / validar encabezados de lista de buzones, analizar / validar la ruta de retorno (que es único entre los encabezados), y así sucesivamente.

El código tal como está escrito tiene una dependencia de javamail, pero es fácil de eliminar si no desea la funcionalidad menor que proporciona.

lacinato
fuente
1
Hola, lo copié en GitHub para el público de la comunidad de código abierto. Ahora todos pueden comentar, documentar y mejorar el código. github.com/bbottema/email-rfc2822-validator . Solía ​​usar la versión anterior de Les, pero tuve que eliminarla debido a errores de congelación de expresiones regulares
Benny Bottema
7

Me pregunto por qué a nadie se le ocurrieron las @Emailrestricciones adicionales del Validador de Hibernate. El validador en sí es EmailValidator.

Markus Malkusch
fuente
Aunque es una alternativa a los comunes de Apache, su implementación es tan rudimentaria como la mayoría de las bibliotecas basadas en expresiones regulares. De los documentos: "Sin embargo, como se analiza en este artículo, no es necesariamente práctico implementar un validador de correo electrónico 100% compatible". El único validador integral basado en expresiones regulares que conozco es email-rfc2822-validator y, de lo contrario, EmailValidator4J parece prometedor.
Benny Bottema
5

Les Hazlewood ha escrito una clase muy valiosa de validación de correo electrónico compatible con RFC 2822 utilizando expresiones regulares de Java. Puede encontrarlo en http://www.leshazlewood.com/?p=23 . Sin embargo, su minuciosidad (o la implementación de Java RE) conduce a la ineficiencia: lea los comentarios sobre los tiempos de análisis para direcciones largas.

Philip
fuente
1
Me basé en la excelente clase de Les Hazlewood (que tiene algunos errores). (Vea mi respuesta por separado a esta pregunta). Aunque mantuve el método jage regex, lo usamos bien en un entorno crítico para el rendimiento. Si todo lo que está haciendo es analizar direcciones, el rendimiento puede ser un problema, pero para la mayoría de los usuarios sospecho que es solo el comienzo de lo que sea que estén haciendo. Mis actualizaciones a la clase también solucionaron varios problemas de recursión larga.
lacinato
Esta es una biblioteca desactualizada y ha sido reemplazada dos veces, finalmente por email-rfc2822-validator . Aunque todavía se adapta a todas las necesidades modernas, también es propenso a errores de rendimiento ocultos (y no admite los cambios limitados por las nuevas especificaciones RFC).
Benny Bottema
3

Porté parte del código en Zend_Validator_Email:

@FacesValidator("emailValidator")
public class EmailAddressValidator implements Validator {

    private String localPart;
    private String hostName;
    private boolean domain = true;

    Locale locale;
    ResourceBundle bundle;

    private List<FacesMessage> messages = new ArrayList<FacesMessage>();

    private HostnameValidator hostnameValidator;

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        setOptions(component);
        String email    = (String) value;
        boolean result  = true;
        Pattern pattern = Pattern.compile("^(.+)@([^@]+[^.])$");
        Matcher matcher = pattern.matcher(email);

        locale = context.getViewRoot().getLocale();
        bundle = ResourceBundle.getBundle("com.myapp.resources.validationMessages", locale);

        boolean length = true;
        boolean local  = true;

        if (matcher.find()) {
            localPart   = matcher.group(1);
            hostName    = matcher.group(2);

            if (localPart.length() > 64 || hostName.length() > 255) {
                length          = false;
                addMessage("enterValidEmail", "email.AddressLengthExceeded");
            } 

            if (domain == true) {
                hostnameValidator = new HostnameValidator();
                hostnameValidator.validate(context, component, hostName);
            }

            local = validateLocalPart();

            if (local && length) {
                result = true;
            } else {
                result = false;
            }

        } else {
            result          = false;
            addMessage("enterValidEmail", "invalidEmailAddress");
        }

        if (result == false) {
            throw new ValidatorException(messages);
        }

    }

    private boolean validateLocalPart() {
        // First try to match the local part on the common dot-atom format
        boolean result = false;

        // Dot-atom characters are: 1*atext *("." 1*atext)
        // atext: ALPHA / DIGIT / and "!", "#", "$", "%", "&", "'", "*",
        //        "+", "-", "/", "=", "?", "^", "_", "`", "{", "|", "}", "~"
        String atext = "a-zA-Z0-9\\u0021\\u0023\\u0024\\u0025\\u0026\\u0027\\u002a"
                + "\\u002b\\u002d\\u002f\\u003d\\u003f\\u005e\\u005f\\u0060\\u007b"
                + "\\u007c\\u007d\\u007e";
        Pattern regex = Pattern.compile("^["+atext+"]+(\\u002e+["+atext+"]+)*$");
        Matcher matcher = regex.matcher(localPart);
        if (matcher.find()) {
            result = true;
        } else {
            // Try quoted string format

            // Quoted-string characters are: DQUOTE *([FWS] qtext/quoted-pair) [FWS] DQUOTE
            // qtext: Non white space controls, and the rest of the US-ASCII characters not
            //   including "\" or the quote character
            String noWsCtl = "\\u0001-\\u0008\\u000b\\u000c\\u000e-\\u001f\\u007f";
            String qText = noWsCtl + "\\u0021\\u0023-\\u005b\\u005d-\\u007e";
            String ws = "\\u0020\\u0009";

            regex = Pattern.compile("^\\u0022(["+ws+qText+"])*["+ws+"]?\\u0022$");
            matcher = regex.matcher(localPart);
            if (matcher.find()) {
                result = true;
            } else {
                addMessage("enterValidEmail", "email.AddressDotAtom");
                addMessage("enterValidEmail", "email.AddressQuotedString");
                addMessage("enterValidEmail", "email.AddressInvalidLocalPart");
            }
        }

        return result;
    }

    private void addMessage(String detail, String summary) {
        String detailMsg = bundle.getString(detail);
        String summaryMsg = bundle.getString(summary);
        messages.add(new FacesMessage(FacesMessage.SEVERITY_ERROR, summaryMsg, detailMsg));
    }

    private void setOptions(UIComponent component) {
        Boolean domainOption = Boolean.valueOf((String) component.getAttributes().get("domain"));
        //domain = (domainOption == null) ? true : domainOption.booleanValue();
    }
}

Con un validador de nombre de host de la siguiente manera:

@FacesValidator("hostNameValidator")
public class HostnameValidator implements Validator {

    private Locale locale;
    private ResourceBundle bundle;
    private List<FacesMessage> messages;
    private boolean checkTld = true;
    private boolean allowLocal = false;
    private boolean allowDNS = true;
    private String tld;
    private String[] validTlds = {"ac", "ad", "ae", "aero", "af", "ag", "ai",
        "al", "am", "an", "ao", "aq", "ar", "arpa", "as", "asia", "at", "au",
        "aw", "ax", "az", "ba", "bb", "bd", "be", "bf", "bg", "bh", "bi", "biz",
        "bj", "bm", "bn", "bo", "br", "bs", "bt", "bv", "bw", "by", "bz", "ca",
        "cat", "cc", "cd", "cf", "cg", "ch", "ci", "ck", "cl", "cm", "cn", "co",
        "com", "coop", "cr", "cu", "cv", "cx", "cy", "cz", "de", "dj", "dk",
        "dm", "do", "dz", "ec", "edu", "ee", "eg", "er", "es", "et", "eu", "fi",
        "fj", "fk", "fm", "fo", "fr", "ga", "gb", "gd", "ge", "gf", "gg", "gh",
        "gi", "gl", "gm", "gn", "gov", "gp", "gq", "gr", "gs", "gt", "gu", "gw",
        "gy", "hk", "hm", "hn", "hr", "ht", "hu", "id", "ie", "il", "im", "in",
        "info", "int", "io", "iq", "ir", "is", "it", "je", "jm", "jo", "jobs",
        "jp", "ke", "kg", "kh", "ki", "km", "kn", "kp", "kr", "kw", "ky", "kz",
        "la", "lb", "lc", "li", "lk", "lr", "ls", "lt", "lu", "lv", "ly", "ma",
        "mc", "md", "me", "mg", "mh", "mil", "mk", "ml", "mm", "mn", "mo",
        "mobi", "mp", "mq", "mr", "ms", "mt", "mu", "museum", "mv", "mw", "mx",
        "my", "mz", "na", "name", "nc", "ne", "net", "nf", "ng", "ni", "nl",
        "no", "np", "nr", "nu", "nz", "om", "org", "pa", "pe", "pf", "pg", "ph",
        "pk", "pl", "pm", "pn", "pr", "pro", "ps", "pt", "pw", "py", "qa", "re",
        "ro", "rs", "ru", "rw", "sa", "sb", "sc", "sd", "se", "sg", "sh", "si",
        "sj", "sk", "sl", "sm", "sn", "so", "sr", "st", "su", "sv", "sy", "sz",
        "tc", "td", "tel", "tf", "tg", "th", "tj", "tk", "tl", "tm", "tn", "to",
        "tp", "tr", "travel", "tt", "tv", "tw", "tz", "ua", "ug", "uk", "um",
        "us", "uy", "uz", "va", "vc", "ve", "vg", "vi", "vn", "vu", "wf", "ws",
        "ye", "yt", "yu", "za", "zm", "zw"};
    private Map<String, Map<Integer, Integer>> idnLength;

    private void init() {
        Map<Integer, Integer> biz = new HashMap<Integer, Integer>();
        biz.put(5, 17);
        biz.put(11, 15);
        biz.put(12, 20);

        Map<Integer, Integer> cn = new HashMap<Integer, Integer>();
        cn.put(1, 20);

        Map<Integer, Integer> com = new HashMap<Integer, Integer>();
        com.put(3, 17);
        com.put(5, 20);

        Map<Integer, Integer> hk = new HashMap<Integer, Integer>();
        hk.put(1, 15);

        Map<Integer, Integer> info = new HashMap<Integer, Integer>();
        info.put(4, 17);

        Map<Integer, Integer> kr = new HashMap<Integer, Integer>();
        kr.put(1, 17);

        Map<Integer, Integer> net = new HashMap<Integer, Integer>();
        net.put(3, 17);
        net.put(5, 20);

        Map<Integer, Integer> org = new HashMap<Integer, Integer>();
        org.put(6, 17);

        Map<Integer, Integer> tw = new HashMap<Integer, Integer>();
        tw.put(1, 20);

        Map<Integer, Integer> idn1 = new HashMap<Integer, Integer>();
        idn1.put(1, 20);

        Map<Integer, Integer> idn2 = new HashMap<Integer, Integer>();
        idn2.put(1, 20);

        Map<Integer, Integer> idn3 = new HashMap<Integer, Integer>();
        idn3.put(1, 20);

        Map<Integer, Integer> idn4 = new HashMap<Integer, Integer>();
        idn4.put(1, 20);

        idnLength = new HashMap<String, Map<Integer, Integer>>();

        idnLength.put("BIZ", biz);
        idnLength.put("CN", cn);
        idnLength.put("COM", com);
        idnLength.put("HK", hk);
        idnLength.put("INFO", info);
        idnLength.put("KR", kr);
        idnLength.put("NET", net);
        idnLength.put("ORG", org);
        idnLength.put("TW", tw);
        idnLength.put("ایران", idn1);
        idnLength.put("中国", idn2);
        idnLength.put("公司", idn3);
        idnLength.put("网络", idn4);

        messages = new ArrayList<FacesMessage>();
    }

    public HostnameValidator() {
        init();
    }

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        String hostName = (String) value;

        locale = context.getViewRoot().getLocale();
        bundle = ResourceBundle.getBundle("com.myapp.resources.validationMessages", locale);

        Pattern ipPattern = Pattern.compile("^[0-9a-f:\\.]*$", Pattern.CASE_INSENSITIVE);
        Matcher ipMatcher = ipPattern.matcher(hostName);
        if (ipMatcher.find()) {
            addMessage("hostname.IpAddressNotAllowed");
            throw new ValidatorException(messages);
        }

        boolean result = false;

        // removes last dot (.) from hostname 
        hostName = hostName.replaceAll("(\\.)+$", "");
        String[] domainParts = hostName.split("\\.");

        boolean status = false;

        // Check input against DNS hostname schema
        if ((domainParts.length > 1) && (hostName.length() > 4) && (hostName.length() < 255)) {
            status = false;

            dowhile:
            do {
                // First check TLD
                int lastIndex = domainParts.length - 1;
                String domainEnding = domainParts[lastIndex];
                Pattern tldRegex = Pattern.compile("([^.]{2,10})", Pattern.CASE_INSENSITIVE);
                Matcher tldMatcher = tldRegex.matcher(domainEnding);
                if (tldMatcher.find() || domainEnding.equals("ایران")
                        || domainEnding.equals("中国")
                        || domainEnding.equals("公司")
                        || domainEnding.equals("网络")) {



                    // Hostname characters are: *(label dot)(label dot label); max 254 chars
                    // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
                    // id-prefix: alpha / digit
                    // ldh: alpha / digit / dash

                    // Match TLD against known list
                    tld = (String) tldMatcher.group(1).toLowerCase().trim();
                    if (checkTld == true) {
                        boolean foundTld = false;
                        for (int i = 0; i < validTlds.length; i++) {
                            if (tld.equals(validTlds[i])) {
                                foundTld = true;
                            }
                        }

                        if (foundTld == false) {
                            status = false;
                            addMessage("hostname.UnknownTld");
                            break dowhile;
                        }
                    }

                    /**
                     * Match against IDN hostnames
                     * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames
                     */
                    List<String> regexChars = getIdnRegexChars();

                    // Check each hostname part
                    int check = 0;
                    for (String domainPart : domainParts) {
                        // Decode Punycode domainnames to IDN
                        if (domainPart.indexOf("xn--") == 0) {
                            domainPart = decodePunycode(domainPart.substring(4));
                        }

                        // Check dash (-) does not start, end or appear in 3rd and 4th positions
                        if (domainPart.indexOf("-") == 0
                                || (domainPart.length() > 2 && domainPart.indexOf("-", 2) == 2 && domainPart.indexOf("-", 3) == 3)
                                || (domainPart.indexOf("-") == (domainPart.length() - 1))) {
                            status = false;
                            addMessage("hostname.DashCharacter");
                            break dowhile;
                        }

                        // Check each domain part
                        boolean checked = false;

                        for (int key = 0; key < regexChars.size(); key++) {
                            String regexChar = regexChars.get(key);
                            Pattern regex = Pattern.compile(regexChar);
                            Matcher regexMatcher = regex.matcher(domainPart);
                            status = regexMatcher.find();
                            if (status) {
                                int length = 63;

                                if (idnLength.containsKey(tld.toUpperCase())
                                        && idnLength.get(tld.toUpperCase()).containsKey(key)) {
                                    length = idnLength.get(tld.toUpperCase()).get(key);
                                }

                                int utf8Length;
                                try {
                                    utf8Length = domainPart.getBytes("UTF8").length;
                                    if (utf8Length > length) {
                                        addMessage("hostname.InvalidHostname");
                                    } else {
                                        checked = true;
                                        break;
                                    }
                                } catch (UnsupportedEncodingException ex) {
                                    Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
                                }


                            }
                        }


                        if (checked) {
                            ++check;
                        }
                    }

                    // If one of the labels doesn't match, the hostname is invalid
                    if (check != domainParts.length) {
                        status = false;
                        addMessage("hostname.InvalidHostnameSchema");

                    }
                } else {
                    // Hostname not long enough
                    status = false;
                    addMessage("hostname.UndecipherableTld");
                }

            } while (false);

            if (status == true && allowDNS) {
                result = true;
            }

        } else if (allowDNS == true) {
            addMessage("hostname.InvalidHostname");
            throw new ValidatorException(messages);
        }

        // Check input against local network name schema;
        Pattern regexLocal = Pattern.compile("^(([a-zA-Z0-9\\x2d]{1,63}\\x2e)*[a-zA-Z0-9\\x2d]{1,63}){1,254}$", Pattern.CASE_INSENSITIVE);
        boolean checkLocal = regexLocal.matcher(hostName).find();
        if (allowLocal && !status) {
            if (checkLocal) {
                result = true;
            } else {
                // If the input does not pass as a local network name, add a message
                result = false;
                addMessage("hostname.InvalidLocalName");
            }
        }


        // If local network names are not allowed, add a message
        if (checkLocal && !allowLocal && !status) {
            result = false;
            addMessage("hostname.LocalNameNotAllowed");
        }

        if (result == false) {
            throw new ValidatorException(messages);
        }

    }

    private void addMessage(String msg) {
        String bundlMsg = bundle.getString(msg);
        messages.add(new FacesMessage(FacesMessage.SEVERITY_ERROR, bundlMsg, bundlMsg));
    }

    /**
     * Returns a list of regex patterns for the matched TLD
     * @param tld
     * @return 
     */
    private List<String> getIdnRegexChars() {
        List<String> regexChars = new ArrayList<String>();
        regexChars.add("^[a-z0-9\\x2d]{1,63}$");
        Document doc = null;
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);

        try {
            InputStream validIdns = getClass().getClassLoader().getResourceAsStream("com/myapp/resources/validIDNs_1.xml");
            DocumentBuilder builder = factory.newDocumentBuilder();
            doc = builder.parse(validIdns);
            doc.getDocumentElement().normalize();
        } catch (SAXException ex) {
            Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ParserConfigurationException ex) {
            Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
        }

        // prepare XPath
        XPath xpath = XPathFactory.newInstance().newXPath();

        NodeList nodes = null;
        String xpathRoute = "//idn[tld=\'" + tld.toUpperCase() + "\']/pattern/text()";

        try {
            XPathExpression expr;
            expr = xpath.compile(xpathRoute);
            Object res = expr.evaluate(doc, XPathConstants.NODESET);
            nodes = (NodeList) res;
        } catch (XPathExpressionException ex) {
            Logger.getLogger(HostnameValidator.class.getName()).log(Level.SEVERE, null, ex);
        }


        for (int i = 0; i < nodes.getLength(); i++) {
            regexChars.add(nodes.item(i).getNodeValue());
        }

        return regexChars;
    }

    /**
     * Decode Punycode string
     * @param encoded
     * @return 
         */
    private String decodePunycode(String encoded) {
        Pattern regex = Pattern.compile("([^a-z0-9\\x2d]{1,10})", Pattern.CASE_INSENSITIVE);
        Matcher matcher = regex.matcher(encoded);
        boolean found = matcher.find();

        if (encoded.isEmpty() || found) {
            // no punycode encoded string, return as is
            addMessage("hostname.CannotDecodePunycode");
            throw new ValidatorException(messages);
        }

        int separator = encoded.lastIndexOf("-");
            List<Integer> decoded = new ArrayList<Integer>();
        if (separator > 0) {
            for (int x = 0; x < separator; ++x) {
                decoded.add((int) encoded.charAt(x));
            }
        } else {
            addMessage("hostname.CannotDecodePunycode");
            throw new ValidatorException(messages);
        }

        int lengthd = decoded.size();
        int lengthe = encoded.length();

        // decoding
        boolean init = true;
        int base = 72;
        int index = 0;
        int ch = 0x80;

        int indexeStart = (separator == 1) ? (separator + 1) : 0;
        for (int indexe = indexeStart; indexe < lengthe; ++lengthd) {
            int oldIndex = index;
            int pos = 1;
            for (int key = 36; true; key += 36) {
                int hex = (int) encoded.charAt(indexe++);
                int digit = (hex - 48 < 10) ? hex - 22
                        : ((hex - 65 < 26) ? hex - 65
                        : ((hex - 97 < 26) ? hex - 97
                        : 36));

                index += digit * pos;
                int tag = (key <= base) ? 1 : ((key >= base + 26) ? 26 : (key - base));
                if (digit < tag) {
                    break;
                }
                pos = (int) (pos * (36 - tag));
            }
            int delta = (int) (init ? ((index - oldIndex) / 700) : ((index - oldIndex) / 2));
            delta += (int) (delta / (lengthd + 1));
            int key;
            for (key = 0; delta > 910; key += 36) {
                delta = (int) (delta / 35);
            }
            base = (int) (key + 36 * delta / (delta + 38));
            init = false;
            ch += (int) (index / (lengthd + 1));
            index %= (lengthd + 1);
            if (lengthd > 0) {
                for (int i = lengthd; i > index; i--) {
                    decoded.set(i, decoded.get(i - 1));
                }
            }

            decoded.set(index++, ch);
        }

        // convert decoded ucs4 to utf8 string
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < decoded.size(); i++) {
            int value = decoded.get(i);
            if (value < 128) {
                sb.append((char) value);
            } else if (value < (1 << 11)) {
                sb.append((char) (192 + (value >> 6)));
                sb.append((char) (128 + (value & 63)));
            } else if (value < (1 << 16)) {
                sb.append((char) (224 + (value >> 12)));
                sb.append((char) (128 + ((value >> 6) & 63)));
                sb.append((char) (128 + (value & 63)));
            } else if (value < (1 << 21)) {
                sb.append((char) (240 + (value >> 18)));
                sb.append((char) (128 + ((value >> 12) & 63)));
                sb.append((char) (128 + ((value >> 6) & 63)));
                sb.append((char) (128 + (value & 63)));
            } else {
                addMessage("hostname.CannotDecodePunycode");
                throw new ValidatorException(messages);
            }
        }

        return sb.toString();

    }

    /**
     * Eliminates empty values from input array
     * @param data
     * @return 
     */
    private String[] verifyArray(String[] data) {
        List<String> result = new ArrayList<String>();
        for (String s : data) {
            if (!s.equals("")) {
                result.add(s);
            }
        }

        return result.toArray(new String[result.size()]);
    }
}

Y un IDNs.xml válido con patrones de expresiones regulares para los diferentes tlds (demasiado grande para incluir :)

<idnlist>
    <idn>
        <tld>AC</tld>
        <pattern>^[\u002d0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$</pattern>
    </idn>
    <idn>
        <tld>AR</tld>
        <pattern>^[\u002d0-9a-zà-ãç-êìíñ-õü]{1,63}$</pattern>
    </idn>
    <idn>
        <tld>AS</tld>
        <pattern>/^[\u002d0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$</pattern>
    </idn>
    <idn>
        <tld>AT</tld>
        <pattern>/^[\u002d0-9a-zà-öø-ÿœšž]{1,63}$</pattern>
    </idn>
    <idn>
        <tld>BIZ</tld>
        <pattern>^[\u002d0-9a-zäåæéöøü]{1,63}$</pattern>
        <pattern>^[\u002d0-9a-záéíñóúü]{1,63}$</pattern>
        <pattern>^[\u002d0-9a-záéíóöúüőű]{1,63}$</pattern>
    </id>
</idlist>
Erick Martinez
fuente
Esta respuesta ya no es aplicable por razones obvias. Elimine la validación de TLD y probablemente sea aceptable si desea aceptar direcciones de correo electrónico que no estén en inglés.
Christopher Schneider
3
public class Validations {

    private Pattern regexPattern;
    private Matcher regMatcher;

    public String validateEmailAddress(String emailAddress) {

        regexPattern = Pattern.compile("^[(a-zA-Z-0-9-\\_\\+\\.)]+@[(a-z-A-z)]+\\.[(a-zA-z)]{2,3}$");
        regMatcher   = regexPattern.matcher(emailAddress);
        if(regMatcher.matches()) {
            return "Valid Email Address";
        } else {
            return "Invalid Email Address";
        }
    }

    public String validateMobileNumber(String mobileNumber) {
        regexPattern = Pattern.compile("^\\+[0-9]{2,3}+-[0-9]{10}$");
        regMatcher   = regexPattern.matcher(mobileNumber);
        if(regMatcher.matches()) {
            return "Valid Mobile Number";
        } else {
            return "Invalid Mobile Number";
        }
    }

    public static void main(String[] args) {

        String emailAddress = "[email protected]";
        String mobileNumber = "+91-9986571622";
        Validations validations = new Validations();
        System.out.println(validations.validateEmailAddress(emailAddress));
        System.out.println(validations.validateMobileNumber(mobileNumber));
    }
}
Suryaprakash Pisay
fuente
2

Si está buscando verificar si una dirección de correo electrónico es válida, entonces VRFY lo ayudará. He encontrado que es útil para validar direcciones de intranet (es decir, direcciones de correo electrónico para sitios internos). Sin embargo, es menos útil para los servidores de correo de Internet (vea las advertencias en la parte superior de esta página)

Brian Agnew
fuente
2

Aunque hay muchas alternativas a los comunes de Apache, sus implementaciones son rudimentarias en el mejor de los casos (como la implementación de los comunes de Apache) ) e incluso están completamente equivocadas en otros casos.

También me mantendría alejado de la expresión regular simple "no restrictiva"; No hay tal cosa. Por ejemplo, @ se permite varias veces según el contexto, ¿cómo sabe que el requerido está allí? Regex simple no lo entenderá, a pesar de que el correo electrónico debe ser válido. Cualquier cosa más compleja se vuelve propensa a errores o incluso contiene asesinos de rendimiento ocultos . ¿Cómo vas a mantener algo como esto ?

El único validador basado en expresiones regulares que cumple con RFC que conozco es email-rfc2822-validator con su expresión 'refinada' apropiadamente llamada Dragons.java . Sin embargo, solo admite la especificación RFC-2822 anterior , aunque es lo suficientemente apropiada para las necesidades modernas (RFC-5322 la actualiza en áreas que ya están fuera del alcance de los casos de uso diario).

Pero lo que realmente quiere es un lexer que analice correctamente una cadena y la divida en la estructura del componente de acuerdo con la gramática RFC. EmailValidator4J parece prometedor en ese sentido, pero aún es joven y limitado.

Otra opción que tiene es usar un servicio web como el servicio web de validación probado por batalla de Mailgun o la API de Mailboxlayer (solo tomó los primeros resultados de Google). No es estrictamente compatible con RFC, pero funciona lo suficientemente bien para las necesidades modernas.

Benny Bottema
fuente
1

¿Qué quieres validar? ¿La direccion de correo electronico?

La dirección de correo electrónico solo se puede verificar por su conformidad de formato. Ver el estándar: RFC2822 . La mejor manera de hacerlo es una expresión regular. Nunca sabrá si realmente existe sin enviar un correo electrónico.

Revisé el validador de bienes comunes. Contiene una clase org.apache.commons.validator.EmailValidator. Parece ser un buen punto de partida.

ReneS
fuente
No estoy seguro de que la expresión regular sea la mejor manera de hacerlo, es bastante ilegible si tiene la intención de seguir el RFC al pie de la letra
user2813274
De acuerdo con @ user2813274, querrás un lexer adecuado, no una expresión regular de espagueti.
Benny Bottema
1

La versión actual del Validador de Apache Commons es 1.3.1 .

La clase que valida es org.apache.commons.validator.EmailValidator. Tiene una importación para org.apache.oro.text.perl.Perl5Util que es de un proyecto retirado de Yakarta ORO .

Por cierto, descubrí que hay una versión 1.4, aquí están los documentos API . En el sitio dice: "Última publicación: 05 de marzo de 2008 | Versión: 1.4-INSTANTÁNEA", pero eso no es definitivo. La única forma de construirse usted mismo (pero esto es una instantánea, no una LIBERACIÓN) y usar o descargar desde aquí . Esto significa que 1.4 no ha sido finalizado por tres años (2008-2011). Esto no está en el estilo de Apache. Estoy buscando una mejor opción, pero no encontré una que sea muy adoptada. Quiero usar algo que esté bien probado, no quiero encontrar ningún error.

niebla
fuente
1.4 INSTANTÁNEA también requiere Jakarta ORO. Apache Commons Validator no es utilizable para mí.
niebla
Finalmente elegí Dr.Vet. La solución de Cumpanasu Florin: mkyong.com/regular-expressions/…
mist
1
Estoy de acuerdo en que el validador de Apache Commons funciona bien, pero creo que es bastante lento, más de 3 ms por llamada.
Nic Cottrell
El rendimiento no es tan importante para mí.
niebla
SNAPSHOT actual (SVN REV 1227719 a partir de ahora) ya no tiene dependencias externas como ORO, ya ni siquiera necesita el módulo de validación completo, las cuatro clases org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator y RegexValidator puede estar solo
Jörg
0

También es posible que desee verificar la longitud: los correos electrónicos tienen un máximo de 254 caracteres. Uso el validador de apache commons y no verifica esto.

minglis
fuente
La especie RFC 2821 (sección 4.5.3.1) especifica una local-partlongitud de 64 y una domainlongitud de 255. (Dicen que más tiempo está permitido por otro software podría ser rechazado)
Sarnold
-2

Parece que no hay bibliotecas perfectas o formas de hacerlo usted mismo, a menos que tenga tiempo para enviar un correo electrónico a la dirección de correo electrónico y esperar una respuesta (aunque esto podría no ser una opción). Terminé usando una sugerencia desde aquí http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/ y ajustando el código para que funcione en Java.

public static boolean isValidEmailAddress(String email) {
    boolean stricterFilter = true; 
    String stricterFilterString = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}";
    String laxString = ".+@.+\\.[A-Za-z]{2}[A-Za-z]*";
    String emailRegex = stricterFilter ? stricterFilterString : laxString;
    java.util.regex.Pattern p = java.util.regex.Pattern.compile(emailRegex);
    java.util.regex.Matcher m = p.matcher(email);
    return m.matches();
}
matt.writes.code
fuente
-2

Este es el mejor método:

public static boolean isValidEmail(String enteredEmail){
        String EMAIL_REGIX = "^[\\\\w!#$%&’*+/=?`{|}~^-]+(?:\\\\.[\\\\w!#$%&’*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\\\.)+[a-zA-Z]{2,6}$";
        Pattern pattern = Pattern.compile(EMAIL_REGIX);
        Matcher matcher = pattern.matcher(enteredEmail);
        return ((!enteredEmail.isEmpty()) && (enteredEmail!=null) && (matcher.matches()));
    }

Fuentes: - http://howtodoinjava.com/2014/11/11/java-regex-validate-email-address/

http://www.rfc-editor.org/rfc/rfc5322.txt

Pravinsingh Waghela
fuente
-2

Otra opción es usar el validador de correo electrónico Hibernate , usando la anotación @Emailo usando la clase de validador programáticamente, como:

import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; 

class Validator {
    // code
    private boolean isValidEmail(String email) {
        EmailValidator emailValidator = new EmailValidator();
        return emailValidator.isValid(email, null);
    }

}
Dherik
fuente
¿Por qué el voto negativo? Es la misma clase utilizada por Hibernate Validator.
Dherik
-3

Aquí está mi enfoque pragmático, donde solo quiero direcciones de dominio blah @ razonables y distintas utilizando los caracteres permitidos del RFC. Las direcciones deben convertirse a minúsculas de antemano.

public class EmailAddressValidator {

    private static final String domainChars = "a-z0-9\\-";
    private static final String atomChars = "a-z0-9\\Q!#$%&'*+-/=?^_`{|}~\\E";
    private static final String emailRegex = "^" + dot(atomChars) + "@" + dot(domainChars) + "$";
    private static final Pattern emailPattern = Pattern.compile(emailRegex);

    private static String dot(String chars) {
        return "[" + chars + "]+(?:\\.[" + chars + "]+)*";
    }

    public static boolean isValidEmailAddress(String address) {
        return address != null && emailPattern.matcher(address).matches();
    }

}
Craig Day
fuente