001/* 002 * Copyright 2008 Les Hazlewood Licensed under the Apache License, Version 2.0 (the "License"); you may not use this 003 * file except in compliance with the License. You may obtain a copy of the License at 004 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software 005 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 006 * either express or implied. See the License for the specific language governing permissions and limitations under the 007 * License. 008 */ 009package org.codemonkey.simplejavamail; 010 011import java.util.regex.Pattern; 012 013/** 014 * Validates an email address according to <a href="http://www.ietf.org/rfc/rfc2822.txt">RFC 2822</a>, using regular expressions. 015 * <p> 016 * From the original author: <br> 017 * <blockquote> If you use this code, please keep the author information in tact and reference my site at <a 018 * href="http://www.leshazlewood.com">leshazlewood.com</a>. Thanks! </blockquote> 019 * <p> 020 * Code sanitized by Benny Bottema (kept validation 100% in tact). 021 * 022 * @author Les Hazlewood, Benny Bottema 023 * @see EmailAddressValidationCriteria 024 */ 025public final class EmailValidationUtil { 026 027 /** 028 * Private constructor; this is a utility class with static methods only, not designed for extension. 029 */ 030 private EmailValidationUtil() { 031 // 032 } 033 034 /** 035 * Validates an e-mail with default validation flags that remains <code>true</code> to RFC 2822. This means allowing both domain 036 * literals and quoted identifiers. 037 * 038 * @param email A complete email address. 039 * @return Whether the e-mail address is compliant with RFC 2822. 040 * @see EmailAddressValidationCriteria#RFC_COMPLIANT 041 */ 042 public static boolean isValid(final String email) { 043 return isValid(email, EmailAddressValidationCriteria.RFC_COMPLIANT); 044 } 045 046 /** 047 * Validates an e-mail with given validation flags. 048 * 049 * @param email A complete email address. 050 * @param emailAddressValidationCriteria A set of flags that restrict or relax RFC 2822 compliance. 051 * @return Whether the e-mail address is compliant with RFC 2822, configured using the passed in {@link EmailAddressValidationCriteria}. 052 * @see EmailAddressValidationCriteria#RFC_COMPLIANT 053 */ 054 public static boolean isValid(final String email, final EmailAddressValidationCriteria emailAddressValidationCriteria) { 055 return buildValidEmailPattern(emailAddressValidationCriteria).matcher(email).matches(); 056 } 057 058 protected static Pattern buildValidEmailPattern(EmailAddressValidationCriteria parameterObject) { 059 // RFC 2822 2.2.2 Structured Header Field Bodies 060 final String wsp = "[ \\t]"; // space or tab 061 final String fwsp = wsp + "*"; 062 // RFC 2822 3.2.1 Primitive tokens 063 final String dquote = "\\\""; 064 // ASCII Control characters excluding white space: 065 final String noWsCtl = "\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F"; 066 // all ASCII characters except CR and LF: 067 final String asciiText = "[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F]"; 068 // RFC 2822 3.2.2 Quoted characters: 069 // single backslash followed by a text char 070 final String quotedPair = "(\\\\" + asciiText + ")"; 071 // RFC 2822 3.2.4 Atom: 072 final String atext = "[a-zA-Z0-9\\!\\#\\$\\%\\&\\'\\*\\+\\-\\/\\=\\?\\^\\_\\`\\{\\|\\}\\~]"; 073 final String atom = fwsp + atext + "+" + fwsp; 074 final String dotAtomText = atext + "+" + "(" + "\\." + atext + "+)*"; 075 final String dotAtom = fwsp + "(" + dotAtomText + ")" + fwsp; 076 // RFC 2822 3.2.5 Quoted strings: 077 // noWsCtl and the rest of ASCII except the doublequote and backslash characters: 078 final String qtext = "[" + noWsCtl + "\\x21\\x23-\\x5B\\x5D-\\x7E]"; 079 final String qcontent = "(" + qtext + "|" + quotedPair + ")"; 080 final String quotedString = dquote + "(" + fwsp + qcontent + ")*" + fwsp + dquote; 081 // RFC 2822 3.2.6 Miscellaneous tokens 082 final String word = "((" + atom + ")|(" + quotedString + "))"; 083 final String phrase = word + "+"; // one or more words. 084 // RFC 1035 tokens for domain names: 085 final String letter = "[a-zA-Z]"; 086 final String letDig = "[a-zA-Z0-9]"; 087 final String letDigHyp = "[a-zA-Z0-9-]"; 088 final String rfcLabel = letDig + "(" + letDigHyp + "{0,61}" + letDig + ")?"; 089 final String rfc1035DomainName = rfcLabel + "(\\." + rfcLabel + ")*\\." + letter + "{2,6}"; 090 // RFC 2822 3.4 Address specification 091 // domain text - non white space controls and the rest of ASCII chars not including [, ], or \: 092 final String dtext = "[" + noWsCtl + "\\x21-\\x5A\\x5E-\\x7E]"; 093 final String dcontent = dtext + "|" + quotedPair; 094 final String domainLiteral = "\\[" + "(" + fwsp + dcontent + "+)*" + fwsp + "\\]"; 095 final String rfc2822Domain = "(" + dotAtom + "|" + domainLiteral + ")"; 096 final String domain = parameterObject.isAllowDomainLiterals() ? rfc2822Domain : rfc1035DomainName; 097 final String localPart = "((" + dotAtom + ")|(" + quotedString + "))"; 098 final String addrSpec = localPart + "@" + domain; 099 final String angleAddr = "<" + addrSpec + ">"; 100 final String nameAddr = "(" + phrase + ")?" + fwsp + angleAddr; 101 final String mailbox = nameAddr + "|" + addrSpec; 102 // now compile a pattern for efficient re-use: 103 // if we're allowing quoted identifiers or not: 104 final String patternString = parameterObject.isAllowQuotedIdentifiers() ? mailbox : addrSpec; 105 return Pattern.compile(patternString); 106 } 107}