1313import java .util .HashMap ;
1414import java .util .Map ;
1515import java .util .regex .Pattern ;
16- import org .apache .commons .validator .routines .DomainValidator ;
17- import org .apache .commons .validator .routines .EmailValidator ;
1816
1917/**
2018 * The email information for the transaction.
@@ -28,6 +26,9 @@ public final class Email extends AbstractModel {
2826 private static final Map <String , String > equivalentDomains ;
2927 private static final Map <String , Boolean > fastmailDomains ;
3028 private static final Map <String , Boolean > yahooDomains ;
29+ private static final Pattern DOMAIN_LABEL_PATTERN = Pattern .compile (
30+ "^[a-zA-Z0-9]$|^[a-zA-Z0-9][a-zA-Z0-9\\ -]*[a-zA-Z0-9]$"
31+ );
3132 private static final Pattern DOT_PATTERN = Pattern .compile ("\\ ." );
3233 private static final Pattern TRAILING_DOT_PATTERN = Pattern .compile ("\\ .+$" );
3334 private static final Pattern REPEAT_COM_PATTERN = Pattern .compile ("(?:\\ .com){2,}$" );
@@ -338,7 +339,7 @@ public Builder(boolean enableValidation) {
338339 * @throws IllegalArgumentException when address is not a valid email address.
339340 */
340341 public Email .Builder address (String address ) {
341- if (enableValidation && !EmailValidator . getInstance (). isValid (address )) {
342+ if (enableValidation && !isValidEmail (address )) {
342343 throw new IllegalArgumentException (
343344 "The email address " + address + " is not valid." );
344345 }
@@ -373,7 +374,7 @@ public Email.Builder hashAddress() {
373374 * @throws IllegalArgumentException when domain is not a valid domain.
374375 */
375376 public Email .Builder domain (String domain ) {
376- if (enableValidation && !DomainValidator . getInstance (). isValid (domain )) {
377+ if (enableValidation && !isValidDomain (domain )) {
377378 throw new IllegalArgumentException ("The email domain " + domain + " is not valid." );
378379 }
379380 this .domain = domain ;
@@ -458,6 +459,34 @@ private String cleanAddress(String address) {
458459 return localPart + "@" + domain ;
459460 }
460461
462+ private static boolean isValidEmail (String email ) {
463+ if (email == null || email .isEmpty ()) {
464+ return false ;
465+ }
466+
467+ // In RFC 5321, the forward path limits the mailbox to 254 characters
468+ // even though a domain can be 255 and the local part 64
469+ if (email .length () > 254 ) {
470+ return false ;
471+ }
472+
473+ int atIndex = email .lastIndexOf ('@' );
474+ if (atIndex <= 0 ) {
475+ return false ;
476+ }
477+
478+ String localPart = email .substring (0 , atIndex );
479+ String domainPart = email .substring (atIndex + 1 );
480+
481+ // The local-part has a maximum length of 64 characters.
482+ if (localPart .length () > 64 ) {
483+ return false ;
484+ }
485+
486+ return isValidDomain (domainPart );
487+ }
488+
489+
461490 private String cleanDomain (String domain ) {
462491 if (domain == null ) {
463492 return null ;
@@ -491,6 +520,48 @@ private String cleanDomain(String domain) {
491520 return domain ;
492521 }
493522
523+ private static boolean isValidDomain (String domain ) {
524+ if (domain == null || domain .isEmpty ()) {
525+ return false ;
526+ }
527+
528+ try {
529+ domain = IDN .toASCII (domain );
530+ } catch (IllegalArgumentException e ) {
531+ return false ;
532+ }
533+
534+ if (domain .endsWith ("." )) {
535+ domain = domain .substring (0 , domain .length () - 1 );
536+ }
537+
538+ if (domain .length () > 255 ) {
539+ return false ;
540+ }
541+
542+ String [] labels = domain .split ("\\ ." );
543+
544+ if (labels .length < 2 ) {
545+ return false ;
546+ }
547+
548+ for (String label : labels ) {
549+ if (!isValidDomainLabel (label )) {
550+ return false ;
551+ }
552+ }
553+
554+ return true ;
555+ }
556+
557+ private static boolean isValidDomainLabel (String label ) {
558+ if (label == null || label .isEmpty () || label .length () > 63 ) {
559+ return false ;
560+ }
561+
562+ return DOMAIN_LABEL_PATTERN .matcher (label ).matches ();
563+ }
564+
494565 /**
495566 * @return The domain of the email address used in the transaction.
496567 */
0 commit comments