java 39 lines · 8 steps

Normalizing email addresses in Java

A validator that canonicalizes emails, applying Gmail's dot and plus-tag rules so equivalent addresses collapse to one form.

Explained by highlit
1public final class EmailNormalizer {
2 
3 private static final Pattern EMAIL_PATTERN = Pattern.compile(
4 "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"
5 );
6 
7 private static final Set<String> GMAIL_DOMAINS = Set.of("gmail.com", "googlemail.com");
8 
9 public String normalize(String rawEmail) {
10 if (rawEmail == null || rawEmail.isBlank()) {
11 throw new InvalidEmailException("Email must not be empty");
12 }
13 
14 String trimmed = rawEmail.strip().toLowerCase(Locale.ROOT);
15 
16 if (!EMAIL_PATTERN.matcher(trimmed).matches()) {
17 throw new InvalidEmailException("Malformed email: " + rawEmail);
18 }
19 
20 int at = trimmed.lastIndexOf('@');
21 String localPart = trimmed.substring(0, at);
22 String domain = trimmed.substring(at + 1);
23 
24 if (GMAIL_DOMAINS.contains(domain)) {
25 int plus = localPart.indexOf('+');
26 if (plus >= 0) {
27 localPart = localPart.substring(0, plus);
28 }
29 localPart = localPart.replace(".", "");
30 domain = "gmail.com";
31 }
32 
33 if (localPart.isEmpty()) {
34 throw new InvalidEmailException("Email local part is empty after normalization");
35 }
36 
37 return localPart + "@" + domain;
38 }
39}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Normalizing to a canonical form lets you treat differently-typed inputs as one identity.
  2. 2Validate structure with a compiled pattern before slicing a string into meaningful parts.
  3. 3Provider-specific rules like Gmail's dot-insensitivity belong behind an explicit domain check.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Normalizing email addresses in Java — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code