Quelle est la meilleure méthode de validation d'adresse e-mail Java? [fermé]

247

Quelles sont les bonnes bibliothèques de validation des adresses e-mail pour Java? Existe-t-il des alternatives au validateur commun ?

jon077
la source
15
Je vais juste laisser ça ici: davidcelis.com/blog/2012/09/06/…
mpenkov
4
URL actuelle des communes: commons.apache.org/proper/commons-validator/apidocs/org/apache/...
james.garriss
Vous ne devriez pas vouloir utiliser des bibliothèques (ou des expressions régulières) qui ne valident pas complètement. En raison de la complexité d'une adresse e-mail valide, il n'y a pas de compromis entre aucune validation et une validation complète. L'implémentation d'Apache Commons n'est pas complète. Je ne connais qu'une seule bibliothèque ( email-rfc2822-validator ), mais elle fonctionne toujours avec d'énormes expressions régulières. Un lexer complet est ce que vous voulez vraiment. EmailValidator4J dit qu'il fait le travail, mais je n'ai pas d'expérience avec cela.
Benny Bottema
1
@BennyBottema Au lieu de modifier la question avec un commentaire, veuillez publier un message Meta pour expliquer pourquoi cela a été fermé si vous avez encore des questions.
Machavity

Réponses:

134

Apache Commons est généralement connu comme un projet solide. Gardez à l'esprit, cependant, vous devrez toujours envoyer un e-mail de vérification à l'adresse si vous voulez vous assurer qu'il s'agit d'un véritable e-mail et que le propriétaire souhaite qu'il soit utilisé sur votre site.

EDIT : il y avait un bug où il était trop restrictif sur le domaine, ce qui l'empêchait d'accepter des e-mails valides de nouveaux TLD.

Ce bogue a été résolu le 03 / Jan / 15 02:48 dans la version 1.4.1 de valideur des communs.

Matthew Flaschen
la source
1
Je suis d'accord avec les éléments supplémentaires que vous avez cités, mais ceux-ci font-ils partie du projet de validation des biens communs?
duffymo
2
Non, la EmailValidatorclasse Apache n'envoie pas d'e-mail pour vérification.
Matthew Flaschen
3
Si votre cas d'utilisation est de valider l'adresse e-mail distante d'un utilisateur, cette solution présente une faille considérable (similaire à InternetAddress.validate ()): EmailValidator considère l'utilisateur @ [10.9.8.7] comme une adresse e-mail valide - ce qu'elles sont selon le RFC, mais peut-être pas pour le formulaire d'inscription / contact utilisateur.
zillion1
1
@zillion, qui est documenté dans Apache COmmons: "Cette implémentation n'est pas garantie de détecter toutes les erreurs possibles dans une adresse e-mail." Et j'ai dit ce que vous devez faire pour "vous assurer qu'il s'agit d'un véritable e-mail". Cependant, les adresses avec des adresses IP locales peuvent être valides dans des environnements rares.
Matthew Flaschen
5
Apache Commons EmailValidator a un sérieux inconvénient: ne prend pas en charge les IDN.
Piohen
261

L'utilisation du package de messagerie Java officiel est la plus simple:

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
la source
59
Notez que InternetAddress.validate () considère l'utilisateur @ [10.9.8.7] et l'utilisateur @ localhost comme des adresses e-mail valides - ce qu'elles sont selon le RFC. Cependant, selon le cas d'utilisation (formulaire Web), vous souhaiterez peut-être les traiter comme non valides.
zillion1
8
non seulement cela est valable comme l'a dit @ zillion1, mais aussi des choses comme bla @ bla sont considérées comme valides. Vraiment pas la meilleure solution.
Diego Plentz
4
@NicholasTolleyCottrell C'est Java, ici nous lançons et prenons des exceptions, je ne comprends pas vraiment votre point
gyorgyabraham
17
Je soupçonne que le constructeur d'InternetAddress a été falsifié. Ou mon système a été trafiqué. Ou RFC822 a été falsifié. Ou je pourrais vraiment utiliser un peu de sommeil maintenant. Mais je viens d'essayer du code et les cinq chaînes suivantes passent toutes comme des adresses e-mail valides si vous les transmettez au constructeur InternetAddress, et "clairement", elles ne sont pas valides. On y va: ., .com, com., abcet 123. De plus, l'ajout d'espaces blancs de début ou de fin n'invalide pas non plus les chaînes. Sois le juge!
Martin Andersson
4
euh, le fromage échoue correctement quand je le lance. à quoi diable la bibliothèque javax.mail liez-vous ???
Aaron Davidson
91

Le validateur Apache Commons peut être utilisé comme mentionné dans les autres réponses.

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'

L'importation:

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

Le code:

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

et pour autoriser les adresses locales

boolean allowLocal = true;
boolean valid = EmailValidator.getInstance(allowLocal).isValid(email);
Aksel Willgert
la source
2
Dans Android Studio, vous pouvez ajouter la compilation «commons-validator: commons-validator: 1.4.1» dans les dépendances de votre application \ build.gradle {}
Benjiko99
2
Après avoir essayé de construire mon projet, il semble qu'apache commons ne fonctionne pas très bien avec Android, des centaines d'avertissements et quelques erreurs, il n'a même pas été compilé. C'est ce que j'ai fini par utiliser howtodoinjava.com/2014/11/11/java-regex-validate-email-address
Benjiko99
1
Même problème avec moi qu'à partir de Benjiko99. Après avoir ajouté la dépendance, le projet ne compilera pas, dit java.exe terminé avec un code de sortie non nul 2.
Amit Mittal
1
J'obtenais également des erreurs dans Android Studio. J'ai changé de 1.4.1 à 1.5.1 et ça marche!
Matt
1
Remarque: Use_the Emailvalidator dans org.apache.commons.validator.routines car EmailValidator dans org.apache.commons.validator est déconseillé (j'utilise le validateur 1.6 commons)
HopeKing
71

Réponse tardive, mais je pense que c'est simple et digne:

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

Cas de test :

entrez la description de l'image ici

À des fins de production, les validations de noms de domaine doivent être effectuées sur le réseau.

Pujan Srivastava
la source
40
C'est un validateur assez brutalement simpliste qui ignore la plupart des règles RFC avec les IDN. J'éviterais cela pour toute application de qualité de production.
mlaccetti
1
[email protected] ne sera pas valide ...
Alexander Burakevych
14
Ne lancez pas votre propre validateur basé sur des expressions rationnelles pour les éléments couverts par les RFC.
Josh Glover
6
réinventer la roue est OK tant que cela ne vous dérange pas le pneu crevé occasionnel
dldnh
c'est bon mais pas pour tous les cas.
Andrain
21

Si vous essayez de faire une validation de formulaire reçue du client, ou juste une validation de bean - restez simple. Il vaut mieux faire une validation de courrier électronique lâche plutôt que de faire une validation stricte et rejeter certaines personnes (par exemple, lorsqu'elles essaient de s'inscrire à votre service Web). Avec presque tout ce qui est autorisé dans la partie nom d'utilisateur de l'e-mail et autant de nouveaux domaines étant ajoutés littéralement chaque mois (par exemple .company, .entreprise, .estate), il est plus sûr de ne pas être restrictif:

Pattern pattern = Pattern.compile("^.+@.+\\..+$");
Matcher matcher = pattern.matcher(email);
Alexander Burakevych
la source
3
c'est un très bon point, toute application raisonnable devrait avoir d'autres mesures pour empêcher cette entrée d'être exploitée de toute façon
jmaculate
4
Que diriez-vous de le changer en "^. + @. + (\\. [^ \\.] +) + $" Pour éviter un point de fin?
Xingang Huang
7

Tard dans la question, ici, mais: je maintiens un cours à cette adresse: http://lacinato.com/cm/software/emailrelated/emailaddress

Il est basé sur la classe de Les Hazlewood, mais a de nombreuses améliorations et corrige quelques bugs. Licence Apache.

Je pense que c'est l'analyseur d'e-mails le plus performant de Java, et je n'ai pas encore vu un autre capable dans n'importe quelle langue, bien qu'il puisse y en avoir un. Ce n'est pas un analyseur de style lexer, mais utilise des expressions Java complexes, et n'est donc pas aussi efficace qu'il pourrait l'être, mais mon entreprise a analysé plus de 10 milliards d'adresses dans le monde réel avec lui: il est certainement utilisable dans une haute performance situation. Peut-être qu'une fois par an, il atteindra une adresse qui provoque un débordement de pile regex (de manière appropriée), mais ce sont des adresses de spam qui comptent des centaines ou des milliers de caractères avec de nombreuses citations et parenthèses, etc.

La RFC 2822 et les spécifications associées sont vraiment assez permissives en termes d'adresses e-mail, donc une classe comme celle-ci est exagérée pour la plupart des utilisations. Par exemple, ce qui suit est une adresse légitime, selon les spécifications, les espaces et tout:

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

Aucun serveur de messagerie ne permettrait cela, mais cette classe peut l'analyser (et le réécrire sous une forme utilisable).

Nous avons trouvé que les options existantes de l'analyseur de courrier électronique Java n'étaient pas suffisamment durables (ce qui signifie qu'elles ne pouvaient pas toutes analyser certaines adresses valides), nous avons donc créé cette classe.

Le code est bien documenté et propose de nombreuses options faciles à modifier pour autoriser ou interdire certains formulaires de courrier électronique. Il fournit également de nombreuses méthodes pour accéder à certaines parties de l'adresse (côté gauche, côté droit, noms personnels, commentaires, etc.), pour analyser / valider les en-têtes de liste de boîtes aux lettres, pour analyser / valider le chemin de retour (qui est unique parmi les en-têtes), etc.

Le code tel qu'il est écrit a une dépendance javamail, mais il est facile à supprimer si vous ne voulez pas les fonctionnalités mineures qu'il fournit.

lacinato
la source
1
Salut, je l'ai copié dans GitHub pour le public de la communauté open source. Maintenant, tout le monde peut commenter, documenter et améliorer le code. github.com/bbottema/email-rfc2822-validator . J'avais l'habitude d'utiliser l'ancienne version de Les, mais j'ai dû la supprimer en raison de bugs de congélation de regex: leshazlewood.com/2006/11/06/emailaddress-java-class/…
Benny Bottema
7

Je me demande simplement pourquoi personne n'est venu @Emaildes contraintes supplémentaires d'Hibernate Validator. Le validateur lui-même l'est EmailValidator.

Markus Malkusch
la source
Bien qu'elle soit une alternative aux communs Apache, son implémentation est aussi rudimentaire que la plupart des bibliothèques basées sur des expressions rationnelles. De la documentation: "Cependant, comme cet article le décrit, il n'est pas nécessairement pratique d'implémenter un validateur de messagerie 100% conforme". Le seul validateur complet basé sur des expressions rationnelles que je connaisse est email-rfc2822-validator et sinon EmailValidator4J semble prometteur.
Benny Bottema
5

Les Hazlewood a écrit une classe de validation d'e-mails conforme à la RFC 2822 très approfondie en utilisant des expressions régulières Java. Vous pouvez le trouver sur http://www.leshazlewood.com/?p=23 . Cependant, sa rigueur (ou l'implémentation de Java RE) conduit à l'inefficacité - lisez les commentaires sur l'analyse des temps pour les adresses longues.

Philippe
la source
1
J'ai construit sur l'excellente classe de Les Hazlewood (qui a quelques bugs). (Voir ma réponse séparée à cette question.) Bien que j'aie conservé la méthode regex java, nous l'utilisons très bien dans un environnement à performances critiques. Si tout ce que vous faites est d'analyser les adresses, les performances peuvent être un problème, mais pour la plupart des utilisateurs, je soupçonne que ce n'est que le début de ce qu'ils font. Mes mises à jour de la classe ont également résolu un certain nombre de problèmes de longue récursivité.
lacinato
Ceci est une bibliothèque obsolète et a été remplacée deux fois, enfin par le validateur email-rfc2822 . Bien qu'il s'adapte toujours à tous les besoins modernes, il est également sujet à des bogues de performances cachés (et ne prend pas en charge les modifications limitées apportées par les nouvelles spécifications RFC).
Benny Bottema
3

J'ai porté une partie du code dans 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();
    }
}

Avec un validateur de nom d'hôte comme suit:

@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()]);
    }
}

Et un validIDNs.xml avec des motifs d'expression régulière pour les différents tlds (trop gros pour être inclus :)

<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
la source
Cette réponse n'est plus applicable pour des raisons évidentes. Supprimez la validation TLD et il est probablement acceptable si vous souhaitez accepter des adresses électroniques non anglaises.
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
la source
2

Si vous cherchez à vérifier si une adresse e-mail est valide, alors VRFY vous aidera. J'ai trouvé que c'était utile pour valider les adresses intranet (c'est-à-dire les adresses e-mail des sites internes). Cependant, il est moins utile pour les serveurs de messagerie Internet (voir les mises en garde en haut de cette page)

Brian Agnew
la source
2

Bien qu'il existe de nombreuses alternatives à Apache commons, leurs implémentations sont au mieux rudimentaires (comme l'implémentation d'Apache commons elle-même) et même mortes dans d'autres cas.

Je resterais également à l'écart de ce que l'on appelle des expressions rationnelles simples et non restrictives; il n'y a rien comme ça. Par exemple, @ est autorisé plusieurs fois en fonction du contexte, comment savez-vous que celui requis est là? Une expression régulière simple ne le comprendra pas, même si l'e-mail doit être valide. Tout ce qui est plus complexe devient sujet aux erreurs ou contient même des tueurs de performances cachés . Comment allez-vous maintenir quelque chose comme ça ?

Le seul validateur basé sur les regex conformes à la RFC complète que je connaisse est le validateur email-rfc2822 avec son regex `` raffiné '' nommé de manière appropriée Dragons.java . Il ne prend en charge que les anciennes spécifications RFC-2822 , bien qu'il soit suffisamment approprié pour les besoins modernes (le RFC-5322 le met à jour dans des domaines déjà hors de portée pour les cas d'utilisation quotidiens).

Mais ce que vous voulez vraiment, c'est un lexer qui analyse correctement une chaîne et la décompose dans la structure des composants selon la grammaire RFC. EmailValidator4J semble prometteur à cet égard, mais est encore jeune et limité.

Vous pouvez également utiliser un service Web tel que le service Web de validation testé par Battlegun ou l' API Mailboxlayer (qui vient de prendre les premiers résultats de Google). Il n'est pas strictement conforme aux RFC, mais fonctionne assez bien pour les besoins modernes.

Benny Bottema
la source
1

Que voulez-vous valider? L'adresse e-mail?

L'adresse e-mail ne peut être vérifiée que pour sa conformité au format. Voir la norme: RFC2822 . La meilleure façon de le faire est une expression régulière. Vous ne saurez jamais s'il existe vraiment sans envoyer un e-mail.

J'ai vérifié le validateur commun. Il contient une classe org.apache.commons.validator.EmailValidator. Semble être un bon point de départ.

ReneS
la source
Je ne suis pas sûr que l'expression régulière soit la meilleure façon de le faire, c'est assez illisible si vous avez l'intention de suivre le RFC à la lettre
user2813274
D'accord avec @ user2813274, vous voudriez un lexer approprié, pas une expression régulière de spaghetti.
Benny Bottema
1

La version actuelle du validateur Apache Commons est 1.3.1 .

La classe qui valide est org.apache.commons.validator.EmailValidator. Il a une importation pour org.apache.oro.text.perl.Perl5Util qui provient d'un projet retiré de Jakarta ORO .

BTW, j'ai trouvé qu'il existe une version 1.4, voici les docs API . Sur le site, il est écrit: "Dernière publication: 5 mars 2008 | Version: 1.4-INSTANTANÉ", mais ce n'est pas définitif. Seul moyen de vous construire (mais il s'agit d'un instantané, pas de publication) et d'utiliser ou de télécharger à partir d' ici . Cela signifie que 1.4 n'a pas été rendu définitif depuis trois ans (2008-2011). Ce n'est pas dans le style d'Apache. Je cherche une meilleure option, mais je n'en ai pas trouvé une qui soit très adoptée. Je veux utiliser quelque chose de bien testé, je ne veux pas rencontrer de bugs.

brouillard
la source
1.4 L'instantané nécessite également Jakarta ORO. Le validateur Apache Commons n'est pas utilisable pour moi.
brouillard
Enfin choisi Dr.Vet. La solution de Cumpanasu Florin: mkyong.com/regular-expressions/…
brouillard
1
Je suis d'accord que le validateur Apache Commons fonctionne bien, mais je trouve qu'il est assez lent - plus de 3 ms par appel.
Nic Cottrell
La performance n'est pas si importante pour moi.
brouillard
L'instantané du tronc actuel (SVN REV 1227719 à partir de maintenant) n'a plus de dépendances externes comme ORO - vous n'avez même plus besoin de l'ensemble du module de validation - les quatre classes org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator et RegexValidator peut se tenir seul
Jörg
0

Vous pouvez également vérifier la longueur - les e-mails contiennent au maximum 254 caractères. J'utilise le validateur apache commons et il ne vérifie pas cela.

minglis
la source
RFC 2821 espèces (section 4.5.3.1) spécifie unlocal-part longueur de 64 et une domainlongueur de 255. (Ils disent que plus de temps est autorisé par pourrait être rejeté par d'autres logiciels.)
sarnold
-2

Il ne semble pas y avoir de bibliothèques ou de moyens parfaits pour le faire vous-même, sauf si vous avez le temps d'envoyer un e-mail à l'adresse e-mail et d'attendre une réponse (cela pourrait ne pas être une option cependant). J'ai fini par utiliser une suggestion d'ici http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/ et ajuster le code pour qu'il fonctionne 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
la source
-2

C'est la meilleure méthode:

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

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

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

Pravinsingh Waghela
la source
-2

Une autre option consiste à utiliser le validateur de messagerie Hibernate , en utilisant l'annotation @Emailou en utilisant la classe de validateur par programme, comme:

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
la source
Pourquoi le downvote? Il s'agit de la même classe utilisée par Hibernate Validator.
Dherik
-3

Voici mon approche pragmatique, où je veux juste des adresses blah @ domain distinctes et raisonnables en utilisant les caractères autorisés du RFC. Les adresses doivent être préalablement converties en minuscules.

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
la source