1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.validator.routines;
18
19 import java.io.Serializable;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22
23
24
25
26
27
28
29
30
31
32
33
34
35 public class EmailValidator implements Serializable {
36
37 private static final long serialVersionUID = 1705927040799295880L;
38
39 private static final String SPECIAL_CHARS = "\\p{Cntrl}\\(\\)<>@,;:'\\\\\\\"\\.\\[\\]";
40 private static final String VALID_CHARS = "(\\\\.)|[^\\s" + SPECIAL_CHARS + "]";
41 private static final String QUOTED_USER = "(\"(\\\\\"|[^\"])*\")";
42 private static final String WORD = "((" + VALID_CHARS + "|')+|" + QUOTED_USER + ")";
43
44 private static final String EMAIL_REGEX = "^(.+)@(\\S+)$";
45 private static final String IP_DOMAIN_REGEX = "^\\[(.*)\\]$";
46 private static final String USER_REGEX = "^" + WORD + "(\\." + WORD + ")*$";
47
48 private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX);
49 private static final Pattern IP_DOMAIN_PATTERN = Pattern.compile(IP_DOMAIN_REGEX);
50 private static final Pattern USER_PATTERN = Pattern.compile(USER_REGEX);
51
52 private static final int MAX_USERNAME_LEN = 64;
53
54
55
56
57
58 private static final EmailValidator EMAIL_VALIDATOR = new EmailValidator(false, false);
59
60
61
62
63
64 private static final EmailValidator EMAIL_VALIDATOR_WITH_TLD = new EmailValidator(false, true);
65
66
67
68
69
70 private static final EmailValidator EMAIL_VALIDATOR_WITH_LOCAL = new EmailValidator(true, false);
71
72
73
74
75
76 private static final EmailValidator EMAIL_VALIDATOR_WITH_LOCAL_WITH_TLD = new EmailValidator(true, true);
77
78
79
80
81
82
83 public static EmailValidator getInstance() {
84 return EMAIL_VALIDATOR;
85 }
86
87
88
89
90
91
92
93
94 public static EmailValidator getInstance(final boolean allowLocal) {
95 return getInstance(allowLocal, false);
96 }
97
98
99
100
101
102
103
104
105
106 public static EmailValidator getInstance(final boolean allowLocal, final boolean allowTld) {
107 if (allowLocal) {
108 if (allowTld) {
109 return EMAIL_VALIDATOR_WITH_LOCAL_WITH_TLD;
110 }
111 return EMAIL_VALIDATOR_WITH_LOCAL;
112 }
113 if (allowTld) {
114 return EMAIL_VALIDATOR_WITH_TLD;
115 }
116 return EMAIL_VALIDATOR;
117 }
118
119 private final boolean allowTld;
120
121 private final DomainValidator domainValidator;
122
123
124
125
126
127
128 protected EmailValidator(final boolean allowLocal) {
129 this(allowLocal, false);
130 }
131
132
133
134
135
136
137
138 protected EmailValidator(final boolean allowLocal, final boolean allowTld) {
139 this.allowTld = allowTld;
140 this.domainValidator = DomainValidator.getInstance(allowLocal);
141 }
142
143
144
145
146
147
148
149
150
151
152 public EmailValidator(final boolean allowLocal, final boolean allowTld, final DomainValidator domainValidator) {
153 this.allowTld = allowTld;
154 if (domainValidator == null) {
155 throw new IllegalArgumentException("DomainValidator cannot be null");
156 }
157 if (domainValidator.isAllowLocal() != allowLocal) {
158 throw new IllegalArgumentException("DomainValidator must agree with allowLocal setting");
159 }
160 this.domainValidator = domainValidator;
161 }
162
163
164
165
166
167
168
169
170 public boolean isValid(final String email) {
171 if (email == null) {
172 return false;
173 }
174 if (email.endsWith(".")) {
175 return false;
176 }
177
178 final Matcher emailMatcher = EMAIL_PATTERN.matcher(email);
179 if (!emailMatcher.matches()) {
180 return false;
181 }
182 if (!isValidUser(emailMatcher.group(1))) {
183 return false;
184 }
185 if (!isValidDomain(emailMatcher.group(2))) {
186 return false;
187 }
188 return true;
189 }
190
191
192
193
194
195
196
197 protected boolean isValidDomain(final String domain) {
198
199 final Matcher ipDomainMatcher = IP_DOMAIN_PATTERN.matcher(domain);
200
201 if (ipDomainMatcher.matches()) {
202 final InetAddressValidator inetAddressValidator =
203 InetAddressValidator.getInstance();
204 return inetAddressValidator.isValid(ipDomainMatcher.group(1));
205 }
206
207 if (allowTld) {
208 return domainValidator.isValid(domain) || !domain.startsWith(".") && domainValidator.isValidTld(domain);
209 }
210 return domainValidator.isValid(domain);
211 }
212
213
214
215
216
217
218
219 protected boolean isValidUser(final String user) {
220
221 if (user == null || user.length() > MAX_USERNAME_LEN) {
222 return false;
223 }
224
225 return USER_PATTERN.matcher(user).matches();
226 }
227
228 }