Was ist die beste Methode zur Überprüfung der Java-E-Mail-Adresse? [geschlossen]

247

Was sind die guten E-Mail-Adressüberprüfungsbibliotheken für Java? Gibt es Alternativen zum Commons Validator ?

jon077
quelle
15
Ich lasse dies einfach hier: davidcelis.com/blog/2012/09/06/…
mpenkov
4
Aktuelle URL für Commons: commons.apache.org/proper/commons-validator/apidocs/org/apache/…
james.garriss
Sie sollten keine Bibliotheken (oder regulären Ausdrücke) verwenden möchten, die nicht umfassend validiert werden. Aufgrund der Komplexität der gültigen E-Mail-Adresse gibt es keinen Mittelweg zwischen keiner Validierung und einer umfassenden Validierung. Die Implementierung von Apache Commons ist nicht umfassend. Mir ist nur eine Bibliothek bekannt ( email-rfc2822-validator ), aber sie funktioniert immer noch mit großen regulären Ausdrücken. Ein umfassender Lexer ist das, was Sie wirklich wollen. EmailValidator4J sagt, dass es den Job macht, aber ich habe keine Erfahrung damit.
Benny Bottema
1
@BennyBottema Anstatt die Frage mit Kommentaren zu bearbeiten, erstellen Sie bitte einen Meta-Beitrag, um zu diskutieren, warum diese geschlossen wurde, wenn Sie noch Fragen haben.
Machavity

Antworten:

134

Apache Commons ist allgemein als solides Projekt bekannt. Beachten Sie jedoch, dass Sie weiterhin eine Bestätigungs-E-Mail an die Adresse senden müssen, wenn Sie sicherstellen möchten, dass es sich um eine echte E-Mail handelt und der Eigentümer möchte, dass sie auf Ihrer Website verwendet wird.

BEARBEITEN : Es gab einen Fehler, bei dem die Domain zu restriktiv war und keine gültigen E-Mails von neuen TLDs akzeptiert wurden.

Dieser Fehler wurde am 03 / Jan / 15 02:48 in Commons-Validator Version 1.4.1 behoben

Matthew Flaschen
quelle
1
Ich stimme den zusätzlichen Bits zu, die Sie zitiert haben, aber sind diese Teile des Commons Validation-Projekts?
Duffymo
2
Nein, die Apache- EmailValidatorKlasse sendet keine E-Mail-Nachricht zur Überprüfung.
Matthew Flaschen
3
Wenn Ihr Anwendungsfall darin besteht, die Remote-E-Mail-Adresse eines Benutzers zu überprüfen, weist diese Lösung einen erheblichen Fehler auf (ähnlich wie bei InternetAddress.validate ()): EmailValidator betrachtet Benutzer @ [10.9.8.7] als gültige E-Mail-Adresse - die sie gemäß der RFC, aber möglicherweise nicht für Benutzerregistrierung / Kontaktformular.
zillion1
1
@zillion, das ist in Apache COmmons dokumentiert: "Es wird nicht garantiert, dass diese Implementierung alle möglichen Fehler in einer E-Mail-Adresse abfängt." Und ich sagte, was Sie tun müssen, um "sicherzustellen, dass es sich um eine echte E-Mail handelt". Adressen mit lokalen IP-Adressen können jedoch in seltenen Umgebungen gültig sein.
Matthew Flaschen
5
Apache Commons EmailValidator hat einen schwerwiegenden Nachteil: IDN wird nicht unterstützt.
Piohen
261

Die Verwendung des offiziellen Java-E-Mail-Pakets ist am einfachsten:

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
quelle
59
Beachten Sie, dass InternetAddress.validate () Benutzer @ [10.9.8.7] und Benutzer @ localhost als gültige E-Mail-Adressen betrachtet - entsprechend dem RFC. Abhängig vom Anwendungsfall (Webformular) möchten Sie sie möglicherweise als ungültig behandeln.
zillion1
8
nicht nur das ist gültig wie @ zillion1 sagte, sondern auch Dinge wie bla @ bla gelten als gültig. Wirklich nicht die beste Lösung.
Diego Plentz
4
@NicholasTolleyCottrell Dies ist Java, hier werfen wir und fangen Ausnahmen, ich verstehe nicht wirklich Ihren Punkt
Gyorgyabraham
17
Ich vermute, dass der InternetAddress-Konstruktor manipuliert wurde. Oder mein System wurde manipuliert. Oder RFC822 wurde manipuliert. Oder ich könnte jetzt wirklich etwas Schlaf gebrauchen. Aber ich habe gerade Code ausprobiert und die folgenden fünf Zeichenfolgen werden alle als gültige E-Mail-Adressen übergeben, wenn Sie sie an den InternetAddress-Konstruktor übergeben, und "eindeutig" sind sie ungültig. Hier gehen wir: ., .com, com., abcund 123. Das Hinzufügen von führenden oder nachfolgenden Leerzeichen macht die Zeichenfolgen ebenfalls nicht ungültig. Du entscheidest!
Martin Andersson
4
ähm, Käse versagt richtig, wenn ich ihn laufen lasse. Was zur Hölle javax.mail Bibliothek verlinkst du ???
Aaron Davidson
91

Der Apache Commons-Validator kann wie in den anderen Antworten erwähnt verwendet werden.

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'

Der Import:

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

Der Code:

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

und um lokale Adressen zuzulassen

boolean allowLocal = true;
boolean valid = EmailValidator.getInstance(allowLocal).isValid(email);
Aksel Willgert
quelle
2
In Android Studio können Sie die Kompilierung 'commons-validator: commons-validator: 1.4.1' zu den Abhängigkeiten Ihrer App \ build.gradle hinzufügen {}
Benjiko99
2
Nachdem ich tatsächlich versucht habe, mein Projekt zu erstellen, scheint es, dass Apache Commons mit Android nicht sehr gut funktioniert, Hunderte von Warnungen und einige Fehler, es wurde nicht einmal kompiliert. Dies ist, was ich am Ende mit howtodoinjava.com/2014/11/11/java-regex-validate-email-address
Benjiko99
1
Gleiches Problem bei mir wie bei Benjiko99. Nach dem Hinzufügen der Abhängigkeit wird das Projekt nicht kompiliert, sagt java.exe beendet mit Exit-Code 2 ungleich Null.
Amit Mittal
1
Ich habe auch in Android Studio Fehler bekommen. Ich habe von 1.4.1 auf 1.5.1 gewechselt und es funktioniert!
Matt
1
Hinweis: Verwenden Sie den Emailvalidator in org.apache.commons.validator.routines, da EmailValidator in org.apache.commons.validator veraltet ist (ich verwende 1.6 commons Validator)
HopeKing
71

Späte Antwort, aber ich denke, es ist einfach und würdig:

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

Testfälle :

Geben Sie hier die Bildbeschreibung ein

Zu Produktionszwecken sollten Domänennamenüberprüfungen netzwerkweise durchgeführt werden.

Pujan Srivastava
quelle
40
Das ist ein ziemlich brutal vereinfachter Validator, der die meisten RFC-Regeln zusammen mit IDNs ignoriert. Ich würde dies für jede App in Produktionsqualität vermeiden.
Mlaccetti
1
[email protected] wird nicht gültig sein ...
Alexander Burakevych
14
Rollen Sie keinen eigenen Regex-basierten Validator für Dinge, die von RFCs abgedeckt werden.
Josh Glover
6
Das Rad neu zu erfinden ist in Ordnung, solange Sie nichts gegen gelegentliche platte Reifen haben
dldnh
es ist gut, aber nicht für alle Fälle.
Andrain
21

Wenn Sie versuchen, eine vom Client erhaltene Formularvalidierung oder nur eine Bean-Validierung durchzuführen, halten Sie es einfach. Es ist besser, eine lose E-Mail-Validierung durchzuführen, als eine strikte durchzuführen und einige Personen abzulehnen (z. B. wenn sie versuchen, sich für Ihren Webdienst zu registrieren). Da fast alles im Benutzernamen der E-Mail erlaubt ist und so viele neue Domains buchstäblich jeden Monat hinzugefügt werden (z. B. Unternehmen, .entreprise, .estate), ist es sicherer, nicht einschränkend zu sein:

Pattern pattern = Pattern.compile("^.+@.+\\..+$");
Matcher matcher = pattern.matcher(email);
Alexander Burakevych
quelle
3
Dies ist ein wirklich guter Punkt, jede vernünftige App sollte andere Maßnahmen haben, um zu verhindern, dass diese Eingabe auf der
ganzen
4
Wie wäre es, wenn Sie es in "^. + @. + (\\. [^ \\.] +) + $" Ändern, um einen nachgestellten Punkt zu vermeiden?
Xingang Huang
7

Spät zur Frage hier, aber: Ich unterhalte eine Klasse unter folgender Adresse: http://lacinato.com/cm/software/emailrelated/emailaddress

Es basiert auf der Klasse von Les Hazlewood, hat jedoch zahlreiche Verbesserungen und behebt einige Fehler. Apache-Lizenz.

Ich glaube, es ist der leistungsfähigste E-Mail-Parser in Java, und ich habe noch keinen fähigeren in einer beliebigen Sprache gesehen, obwohl es möglicherweise einen gibt. Es ist kein Parser im Lexer-Stil, verwendet jedoch einen komplizierten Java-Regex und ist daher nicht so effizient wie es sein könnte, aber mein Unternehmen hat damit weit über 10 Milliarden reale Adressen analysiert: Es ist sicherlich für eine hohe Leistung verwendbar Lage. Vielleicht trifft es einmal im Jahr eine Adresse, die (entsprechend) einen Überlauf des Regex-Stapels verursacht, aber dies sind Spam-Adressen, die Hunderte oder Tausende von Zeichen lang sind und viele, viele Anführungszeichen und Klammern und dergleichen enthalten.

RFC 2822 und die zugehörigen Spezifikationen sind in Bezug auf E-Mail-Adressen sehr zulässig. Daher ist eine Klasse wie diese für die meisten Verwendungszwecke zu viel des Guten. Zum Beispiel ist das Folgende eine legitime Adresse, je nach Spezifikation, Leerzeichen und allem:

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

Kein Mailserver würde dies zulassen, aber diese Klasse kann es analysieren (und in ein verwendbares Formular umschreiben).

Wir haben festgestellt, dass die vorhandenen Java-E-Mail-Parser-Optionen nicht ausreichend dauerhaft sind (dh alle konnten einige gültige Adressen nicht analysieren). Daher haben wir diese Klasse erstellt.

Der Code ist gut dokumentiert und bietet viele einfach zu ändernde Optionen, um bestimmte E-Mail-Formulare zuzulassen oder zu verbieten. Es bietet auch viele Methoden, um auf bestimmte Teile der Adresse zuzugreifen (linke Seite, rechte Seite, persönliche Namen, Kommentare usw.), Mailboxlisten-Header zu analysieren / zu validieren und den Rückweg zu analysieren / validieren (was unter den Überschriften einzigartig ist) und so weiter.

Der geschriebene Code hat eine Javamail-Abhängigkeit, kann jedoch leicht entfernt werden, wenn Sie die darin enthaltenen geringfügigen Funktionen nicht möchten.

Lacinato
quelle
1
Hallo, ich habe es in GitHub für die Öffentlichkeit der Open Source Community kopiert. Jetzt kann jeder den Code kommentieren, dokumentieren und verbessern. github.com/bbottema/email-rfc2822-validator . Früher habe ich die ältere Version von Les verwendet, aber ich musste sie aufgrund von Regex-Einfrierfehlern entfernen: leshazlewood.com/2006/11/06/emailaddress-java-class/…
Benny Bottema
7

Ich frage mich nur, warum sich niemand @Emaildie zusätzlichen Einschränkungen von Hibernate Validator ausgedacht hat. Der Validator selbst ist EmailValidator.

Markus Malkusch
quelle
Obwohl es sich um eine Alternative zu Apache Commons handelt, ist seine Implementierung ebenso rudimentär wie die der meisten auf Regex basierenden Bibliotheken. Aus den Dokumenten: "Wie in diesem Artikel erläutert, ist es jedoch nicht unbedingt praktisch, einen 100% kompatiblen E-Mail-Validator zu implementieren." Der einzige Regex-basierte umfassende Validator, den ich kenne, ist email-rfc2822-validator, und ansonsten scheint EmailValidator4J vielversprechend.
Benny Bottema
5

Les Hazlewood hat eine sehr gründliche RFC 2822-kompatible E-Mail-Validierungsklasse mit regulären Java-Ausdrücken geschrieben. Sie finden es unter http://www.leshazlewood.com/?p=23 . Die Gründlichkeit (oder die Java RE-Implementierung) führt jedoch zu Ineffizienz. Lesen Sie die Kommentare zu den Analysezeiten für lange Adressen.

Philip
quelle
1
Ich habe auf Les Hazlewoods exzellenter Klasse aufgebaut (die einige Fehler hat). (Siehe meine separate Antwort auf diese Frage.) Obwohl ich die Java-Regex-Methode beibehalten habe, verwenden wir sie in einer leistungskritischen Umgebung einwandfrei. Wenn Sie nur Adressen analysieren, ist die Leistung möglicherweise ein Problem, aber für die meisten Benutzer würde ich vermuten, dass dies nur der Anfang dessen ist, was sie tun. Meine Aktualisierungen der Klasse haben auch eine Reihe von Problemen mit langer Rekursion behoben.
Lacinato
Dies ist eine veraltete Bibliothek und wurde zweimal ersetzt, schließlich durch email-rfc2822-validator . Obwohl es immer noch allen modernen Anforderungen entspricht, ist es auch immer noch anfällig für versteckte Leistungsfehler (und unterstützt die begrenzten Änderungen durch die neueren RFC-Spezifikationen nicht).
Benny Bottema
3

Ich habe einen Teil des Codes in Zend_Validator_Email portiert:

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

Mit einem Hostnamen-Validator wie folgt:

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

Und eine validIDNs.xml mit Regex-Mustern für die verschiedenen tlds (zu groß, um sie einzuschließen :)

<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
quelle
Diese Antwort ist aus offensichtlichen Gründen nicht mehr anwendbar. Entfernen Sie die TLD-Validierung und es ist wahrscheinlich akzeptabel, wenn Sie nicht englische E-Mail-Adressen akzeptieren möchten.
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
quelle
2

Wenn Sie überprüfen möchten , ob eine E-Mail-Adresse gültig ist, hilft Ihnen VRFY dabei . Ich habe festgestellt, dass es nützlich ist, um Intranetadressen zu überprüfen ( dh E-Mail-Adressen für interne Websites). Für Internet-Mail-Server ist dies jedoch weniger nützlich (siehe die Einschränkungen oben auf dieser Seite).

Brian Agnew
quelle
2

Obwohl es viele Alternativen zu Apache Commons gibt, sind ihre Implementierungen bestenfalls rudimentär (wie die Implementierung von Apache Commons selbst) und in anderen Fällen sogar absolut falsch.

Ich würde mich auch von so genannten einfachen "nicht einschränkenden" Regex fernhalten. Das gibt es nicht. Zum Beispiel ist @ je nach Kontext mehrmals zulässig. Woher wissen Sie, dass das erforderliche vorhanden ist? Einfache Regex wird es nicht verstehen, obwohl die E-Mail gültig sein sollte. Alles , was komplexer ist, wird fehleranfällig oder enthält sogar versteckte Leistungskiller . Wie wollen Sie so etwas wie halten diese ?

Der einzige mir bekannte umfassende RFC-kompatible Regex-basierte Validator ist der E-Mail-rfc2822-Validator mit seinem 'verfeinerten' Regex mit dem passenden Namen Dragons.java . Es unterstützt jedoch nur die ältere RFC-2822- Spezifikation, obwohl dies für moderne Anforderungen geeignet ist (RFC-5322) aktualisiert sie in Bereichen, die für den täglichen Gebrauch bereits nicht verfügbar sind).

Aber was Sie wirklich wollen, ist ein Lexer , der einen String richtig analysiert und ihn gemäß der RFC-Grammatik in die Komponentenstruktur aufteilt.EmailValidator4J scheint in dieser Hinsicht vielversprechend, ist aber noch jung und begrenzt.

Eine weitere Option ist die Verwendung eines Webservices wie Mailguns kampferprobtem Validierungs-Webservice oder der Mailboxlayer-API (nur die ersten Google-Ergebnisse wurden verwendet). Es ist nicht streng RFC-konform, funktioniert aber gut genug für moderne Anforderungen.

Benny Bottema
quelle
1

Was möchten Sie validieren? Die E-Mail Adresse?

Die E-Mail-Adresse kann nur auf Formatkonformität überprüft werden. Siehe Standard: RFC2822 . Der beste Weg, dies zu tun, ist ein regulärer Ausdruck. Sie werden nie wissen, ob es wirklich existiert, ohne eine E-Mail zu senden.

Ich habe den Commons-Validator überprüft. Es enthält eine org.apache.commons.validator.EmailValidator-Klasse. Scheint ein guter Ausgangspunkt zu sein.

ReneS
quelle
Ich bin nicht sicher, ob der Regex der beste Weg ist, dies zu tun. Es ist ziemlich unlesbar, wenn Sie beabsichtigen, dem RFC bis zum Buchstaben zu folgen
user2813274
Stimmen Sie mit @ user2813274 überein, Sie möchten einen richtigen Lexer, keinen Spaghetti Regex.
Benny Bottema
1

Die aktuelle Apache Commons Validator-Version ist 1.3.1 .

Die validierende Klasse ist org.apache.commons.validator.EmailValidator. Es hat einen Import für org.apache.oro.text.perl.Perl5Util, der aus einem pensionierten ORO-Projekt in Jakarta stammt .

Übrigens habe ich festgestellt, dass es eine 1.4-Version gibt, hier sind die API-Dokumente . Auf der Website heißt es: "Zuletzt veröffentlicht: 05. März 2008 | Version: 1.4-SNAPSHOT", aber das ist nicht endgültig. Nur so können Sie sich selbst erstellen (dies ist jedoch ein Schnappschuss, nicht RELEASE) und verwenden oder von hier herunterladen . Dies bedeutet, dass 1.4 seit drei Jahren (2008-2011) nicht endgültig ist. Dies ist nicht in Apaches Stil. Ich suche nach einer besseren Option, habe aber keine gefunden, die sehr gut angenommen wird. Ich möchte etwas verwenden, das gut getestet ist, und keine Fehler finden.

Nebel
quelle
1.4 SNAPSHOT erfordert auch Jakarta ORO. Apache Commons Validator kann für mich nicht verwendet werden.
Nebel
Schließlich entschied sich Dr.Vet. Cumpanasu Florins Lösung: mkyong.com/regular-expressions/…
Nebel
1
Ich bin damit einverstanden, dass der Apache Commons-Validator gut funktioniert, finde ihn jedoch recht langsam - über 3 ms pro Anruf.
Nic Cottrell
Leistung ist für mich nicht so wichtig.
Nebel
Der aktuelle Trunk SNAPSHOT (SVN REV 1227719 ab sofort) hat keine externen Abhängigkeiten wie ORO mehr - Sie benötigen nicht einmal mehr das gesamte Validierungsmodul - die vier Klassen org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator und RegexValidator können alleine stehen
Jörg
0

Möglicherweise möchten Sie auch die Länge überprüfen - E-Mails sind maximal 254 Zeichen lang. Ich benutze den Apache Commons Validator und er prüft dies nicht.

Minglis
quelle
RFC 2821- Arten (Abschnitt 4.5.3.1) spezifizieren eine local-partLänge von 64 und adomain Länge von 255. (Sie sagen, dass länger erlaubt ist, könnte von anderer Software abgelehnt werden.)
Sarnold
-2

Es scheint keine perfekten Bibliotheken oder Möglichkeiten zu geben, dies selbst zu tun, es sei denn, Sie müssen Zeit haben, eine E-Mail an die E-Mail-Adresse zu senden und auf eine Antwort zu warten (dies ist jedoch möglicherweise keine Option). Am Ende habe ich einen Vorschlag von hier http://blog.logichigh.com/2010/09/02/validating-an-e-mail-address/ verwendet und den Code so angepasst, dass er in Java funktioniert.

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
quelle
-2

Dies ist die beste Methode:

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

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

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

Pravinsingh Waghela
quelle
-2

Eine andere Option ist die Verwendung des E-Mail-Validators im Ruhezustand , die Verwendung der Anmerkung @Emailoder die programmgesteuerte Verwendung der Validator-Klasse, z.

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
quelle
Warum das Downvote? Es ist dieselbe Klasse, die auch von Hibernate Validator verwendet wird.
Dherik
-3

Hier ist mein pragmatischer Ansatz, bei dem ich nur vernünftige eindeutige blah @ domain-Adressen mit den zulässigen Zeichen aus dem RFC möchte. Adressen müssen vorher in Kleinbuchstaben umgewandelt werden.

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
quelle