@@ -93,20 +93,6 @@ public static void enforceValid(String email) throws InvalidEmailException {
93
93
}
94
94
}
95
95
96
- /**
97
- * Determine if the given email address is valid, returning a new {@link EmailValidationResult}
98
- * object that contains details on the result of the validation. Use this method if you need to
99
- * see the {@link FailureReason} upon validation failure. See {@link #tryParse(String)}
100
- * for details on what is required of an email address within basic validation.
101
- *
102
- * @param email the email address to validate
103
- * @return a {@link EmailValidationResult} containing success or failure, along with the parsed
104
- * {@link Email} object if successful, or the {@link FailureReason} if not
105
- */
106
- public static EmailValidationResult validate (String email ) {
107
- return validateInternal (email );
108
- }
109
-
110
96
/**
111
97
* Parse the given email address into a new {@link Email} object. This method does basic
112
98
* validation on the input email address. This method does not claim to be 100%
@@ -123,18 +109,44 @@ public static EmailValidationResult validate(String email) {
123
109
* is invalid
124
110
*/
125
111
public static Optional <Email > tryParse (String email ) {
126
- EmailValidationResult result = validateInternal (email );
112
+ EmailValidationResult result = validate (email );
127
113
128
114
return result .getEmail ();
129
115
}
130
116
117
+ /**
118
+ * Determine if the given email address is valid, returning a new {@link EmailValidationResult}
119
+ * object that contains details on the result of the validation. Use this method if you need to
120
+ * see the {@link FailureReason} upon validation failure. See {@link #tryParse(String)}
121
+ * for details on what is required of an email address within basic validation.
122
+ *
123
+ * @param email the email address to validate
124
+ * @return a {@link EmailValidationResult} containing success or failure, along with the parsed
125
+ * {@link Email} object if successful, or the {@link FailureReason} if not
126
+ */
127
+ public static EmailValidationResult validate (String email ) {
128
+ return validateInternal (email , false );
129
+ }
130
+
131
+ /**
132
+ * Package-private validate method that exposes an additional option {@code allowGmailDots}.
133
+ *
134
+ * @param email the email address to parse and validate
135
+ * @param allowGmailDots true if a leading or trailing dot in the local-part should be allowed
136
+ * @return a {@link EmailValidationResult} containing success or failure, along with the parsed
137
+ * {@link Email} object if successful, or the {@link FailureReason} if not
138
+ */
139
+ static EmailValidationResult validate (String email , boolean allowGmailDots ) {
140
+ return validateInternal (email , allowGmailDots );
141
+ }
142
+
131
143
/**
132
144
* Internal parsing method.
133
145
*
134
146
* @param email the email address to parse
135
147
* @return a new {@link Email} instance if valid, empty if invalid
136
148
*/
137
- private static EmailValidationResult validateInternal (String email ) {
149
+ private static EmailValidationResult validateInternal (String email , boolean allowGmailDots ) {
138
150
// email cannot be null
139
151
if (email == null ) return EmailValidationResult .failure (FailureReason .NULL_ADDRESS );
140
152
@@ -168,7 +180,11 @@ private static EmailValidationResult validateInternal(String email) {
168
180
if (size > 320 ) return EmailValidationResult .failure (FailureReason .ADDRESS_TOO_LONG );
169
181
170
182
// email cannot start with '.'
171
- if (email .charAt (0 ) == '.' ) return EmailValidationResult .failure (FailureReason .STARTS_WITH_DOT );
183
+ // email cannot start with '.'
184
+ // unless we are configured to allow it (GMail doesn't care about a starting dot)
185
+ if (email .charAt (0 ) == '.' && !allowGmailDots ) {
186
+ return EmailValidationResult .failure (FailureReason .STARTS_WITH_DOT );
187
+ }
172
188
173
189
// email cannot end with '.'
174
190
if (email .charAt (size - 1 ) == '.' ) {
@@ -223,7 +239,8 @@ private static EmailValidationResult validateInternal(String email) {
223
239
return EmailValidationResult .failure (FailureReason .UNQUOTED_ANGLED_BRACKET );
224
240
}
225
241
226
- EmailValidationResult innerResult = validateInternal (email .substring (i + 1 , size - 1 ));
242
+ EmailValidationResult innerResult
243
+ = validateInternal (email .substring (i + 1 , size - 1 ), allowGmailDots );
227
244
228
245
// If the address passed validation, return success with the identifier included.
229
246
// Otherwise, just return the failed internal result
@@ -512,7 +529,15 @@ private static EmailValidationResult validateInternal(String email) {
512
529
513
530
// Check that local-part does not end with '.'
514
531
if (localPart .charAt (localPart .length () - 1 ) == '.' ) {
515
- return EmailValidationResult .failure (FailureReason .LOCAL_PART_ENDS_WITH_DOT );
532
+ // unless we are configured to allow it (GMail doesn't care about a trailing dot)
533
+ if (!allowGmailDots ) {
534
+ return EmailValidationResult .failure (FailureReason .LOCAL_PART_ENDS_WITH_DOT );
535
+ }
536
+
537
+ // if we allow a trailing dot, just make sure it's not the only thing in the local-part
538
+ if (localPartLen <= 1 ) {
539
+ return EmailValidationResult .failure (FailureReason .LOCAL_PART_MISSING );
540
+ }
516
541
}
517
542
518
543
// Ensure the TLD is not empty or greater than 63 chars
0 commit comments