Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

What are the good email address validation libraries for Java? Are there any alternatives to commons validator?

share|improve this question
1  
Here is the specific commons-validator class for validating emails: commons.apache.org/validator/api-1.3.1/org/apache/commons/… – jon077 Aug 29 '10 at 2:10
2  
I'll just leave this here: davidcelis.com/blog/2012/09/06/… – misha Oct 30 '12 at 6:44

14 Answers

up vote 23 down vote accepted

Apache Commons is generally known as a solid project. Keep in mind, though, you'll still have to send a verification email to the address if you want to ensure it's a real email, and that the owner wants it used on your site.

share|improve this answer
1  
I agree with the extra bits you cited, but are those part of the Commons Validation project? – duffymo Mar 9 '09 at 0:33
No, the Apache EmailValidator class does not send an email message for verification. – Matthew Flaschen Jul 14 '11 at 18:34
2  
If your use case is to validate a user's remote email address, this solution has a considerable flaw (similar to InternetAddress.validate()): EmailValidator considers user@[10.9.8.7] as a valid email addresses - which they are according to the RFC, but maybe not for user registration/contact form. – zillion1 Oct 5 '11 at 9:45
@zillion, that is documented in Apache COmmons: "This implementation is not guaranteed to catch all possible errors in an email address." And I said what you have to do to "ensure it's a real email". Addresses with local IPs could be valid in rare environments, though. – Matthew Flaschen Oct 5 '11 at 22:11
@Matthew Flaschen: I just wanted to point this out. Using Common's EmailValidator myself, I'm not saying that is is bad in general. – zillion1 Oct 6 '11 at 8:28

Using the official java email package is the easiest:

public static boolean isValidEmailAddress(String email) {
   boolean result = true;
   try {
      InternetAddress emailAddr = new InternetAddress(email);
      emailAddr.validate();
   } catch (AddressException ex) {
      result = false;
   }
   return result;
}
share|improve this answer
in the easiest and you probably already have it in your project to send emails – Eduardo Sep 1 '11 at 20:37
12  
Note that InternetAddress.validate() considers user@[10.9.8.7] and user@localhost as valid email addresses - which they are according to the RFC. Though, depending on the use case (web form), you might want to treat them as invalid. – zillion1 Oct 5 '11 at 8:30
1  
not only that is valid as @zillion1 said, but also things like bla@bla are considered valid. Really not the best solution. – Diego Plentz Nov 20 '12 at 17:30
3  
@NicholasTolleyCottrell This is Java, here we throw and catch exceptions, I don't really get your point – gyabraham Jan 25 at 15:44
1  
I suspect that InternetAddress constructor has been tampered with. Or my system has been tampered with. Or RFC822 has been tampered with. Or I could really use some sleep right now. But I just tried some code and the following five strings all pass as valid e-mail addresses if you pass them to the InternetAddress constructor, and "clearly", they are not valid. Here we go: ., .com, com., abc and 123. Also, adding leading or trailing white space do not invalidate the strings either. You be the judge! – Martin Andersson Mar 19 at 21:12
show 4 more comments

http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/

share|improve this answer
1  
The referenced regexp is way too simple. See ex-parrot.com/~pdw/Mail-RFC822-Address.html for a correct (?) approach. – Joe23 Jul 4 '11 at 9:32
It is not just too simple, it won't support Internationalized Domain Names. – Paweł Dyda Dec 16 '11 at 12:56

Les Hazlewood has written a very thorough RFC 2822 compliant email validator class using Java regular expressions. You can find it at http://www.leshazlewood.com/?p=23. However, its thoroughness (or the Java RE implementation) leads to inefficiency - read the comments about parsing times for long addresses.

share|improve this answer
1  
I built upon Les Hazlewood's excellent class (which does have some bugs). (See my separate answer to this question.) Though I did maintain the java regex method, we use it just fine in a performance-critical environment. If all you're doing is parsing addresses, the performance may be an issue, but for most users I'd suspect it's just the beginning of whatever they're doing. My updates to the class did also fix a number of long-recursion issues. – lacinato Oct 30 '12 at 6:41

I ported some of the code in 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();
    }
}

With a hostname validator as follows:

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

And a validIDNs.xml with regex patterns for the different tlds (too big to include:)

<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>
share|improve this answer

What do you want to validate? The email address?

The email address can only be checked for its format conformance. See the standard: RFC2822. Best way to do that is a regular expression. You will never know if really exists without sending an email.

I checked the commons validator. It contains an org.apache.commons.validator.EmailValidator class. Seems to be a good starting point.

share|improve this answer

Current Apache Commons Validator version is 1.3.1.

Class that validates is org.apache.commons.validator.EmailValidator. It has an import for org.apache.oro.text.perl.Perl5Util which is from a retired Jakarta ORO project.

BTW, I found that there is a 1.4 version, here are the API docs. On the site it says: "Last Published: 05 March 2008 | Version: 1.4-SNAPSHOT", but that's not final. Only way to build yourself (but this is a snapshot, not RELEASE) and use, or download from here. This means 1.4 has not been made final for three years (2008-2011). This is not in Apache's style. I'm looking for a better option, but didn't find one that is very adopted. I want to use something that is well tested, don't want to hit any bugs.

share|improve this answer
1.4 SNAPSHOT also requires Jakarta ORO. Apache Commons Validator is not usable for me. – mist Apr 3 '11 at 18:09
Finally chose Dr.Vet. Cumpanasu Florin's solution: mkyong.com/regular-expressions/… – mist Apr 3 '11 at 20:06
1  
I agree that the Apache Commons validator works well, but I find it to be quite slow - over 3ms per call. – Nicholas Tolley Cottrell Feb 1 '12 at 15:57
Performance is not that important for me. – mist Feb 3 '12 at 8:55
current trunk SNAPSHOT (SVN REV 1227719 as of now) has no external dependencies like ORO anymore - you don't even need the whole validation module anymore - the four classes org.apache.commons.validator.routines.EmailValidator, InetAddressValidator, DomainValidator and RegexValidator are able to stand alone – Jörg Feb 15 '12 at 10:58

If you're looking to verify whether an email address is valid, then VRFY will get you some of the way. I've found it's useful for validating intranet addresses (that is, email addresses for internal sites). However it's less useful for internet mail servers (see the caveats at the top of this page)

share|improve this answer

You may also want to check for the length - emails are a maximum of 254 chars long. I use the apache commons validator and it doesn't check for this.

share|improve this answer
RFC 2821 species (section 4.5.3.1) specifies a local-part length of 64 and a domain length of 255. (They do say that longer is allowed by might be rejected by other software.) – sarnold Nov 23 '11 at 7:44

Late to the question, here, but: I maintain a class at this address: http://lacinato.com/cm/software/emailrelated/emailaddress

It is based on Les Hazlewood's class, but has numerous improvements and fixes a few bugs. Apache license.

I believe it is the most capable email parser in Java, and I have yet to see one more capable in any language, though there may be one out there. It's not a lexer-style parser, but uses some complicated java regex, and thus is not as efficient as it could be, but my company has parsed well over 10 billion real-world addresses with it: it's certainly usable in a high-performance situation. Maybe once a year it'll hit an address that causes a regex stack overflow (appropriately), but these are spam addresses which are hundreds or thousands of characters long with many many quotes and parenthesis and the like.

RFC 2822 and the related specs are really quite permissive in terms of email addresses, so a class like this is overkill for most uses. For example, the following is a legitimate address, according to spec, spaces and all:

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

No mail server would allow that, but this class can parse it (and rewrite it to a usable form).

We found the existing Java email parser options to be insufficiently durable (meaning, all of them could not parse some valid addresses), so we created this class.

The code is well-documented and has a lot of easy-to-change options to allow or disallow certain email forms. It also provides a lot of methods to access certain parts of the address (left-hand side, right-hand side, personal names, comments, etc), to parse/validate mailbox-list headers, to parse/validate the return-path (which is unique among the headers), and so forth.

The code as written has a javamail dependency, but it's easy to remove if you don't want the minor functionality it provides.

share|improve this answer

Late answer, but I think it is simple and worthy

public boolean isValidEmailAddress(String email) {
       java.util.regex.Pattern p = java.util.regex.Pattern.compile(".+@.+\\.[a-z]+");
       java.util.regex.Matcher m = p.matcher(email);
       boolean matchFound = m.matches();
       return matchFound;
}
share|improve this answer
public void EmailCheck(View v) // This is pattern method import by regular class
{
    String str = "";
    emailid = emailID.getText().toString();

    if(emailid.equalsIgnoreCase(str))
    {
        System.out.println("Please enter your email id");
     }
    else
    {
        Pattern p =Pattern.compile("[a-zA-Z0-9_.]*@[a-zA-Z]*.[a-zA-Z]*");
        Matcher m = p.matcher(emailid);
        boolean bm = m.matches();

        if(bm == true)
        {
            System.out.println("email id is valid");

        }
        else
        {
            System.out.println("email id is Invalid, Re-try again");

        }
    }
}
share|improve this answer

EmailValidator from Apache Commons is now deprecated, so please don't use it. If you import it in Eclipse, you will see be able to see a strikethrough

share|improve this answer

Spring has wonderful validation classes. But I don't see what these or the Commons Validation have to do with e-mail. They're for general validation and binding of values, like HTTP request parameters, to objects. How do you connect them to e-mail? What are you validating? E-mail addresses can be validated with regular expressions. What else is there?

share|improve this answer
Yes, they can be validated by regex, and in fact that is how Apache's EmailValidator does it (svn.apache.org/viewvc/commons/proper/validator/trunk/src/main/…) . But the point is, don't reinvent the wheel. – Matthew Flaschen Mar 9 '09 at 0:09
"library" to validate an e-mail address? Sorry, it sounded like far more than that was required. I must have misinterpreted the question. – duffymo Mar 9 '09 at 0:32
2  
I would hardly characterize redoing a regular expression as reinventing a wheel. There's another argument that says you'd be better off without the dependency on another 3rd party library. Our host Jeff Atwood agrees: codinghorror.com/blog/archives/001145.html – duffymo Mar 9 '09 at 13:07

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.