Skip to content

Commit 2921d7a

Browse files
committed
fix valid email address
1 parent 5f33ef8 commit 2921d7a

File tree

5 files changed

+98
-44
lines changed

5 files changed

+98
-44
lines changed

src/string/.idea/.gitignore

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/string/.idea/modules.xml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/string/.idea/string.iml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/string/.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/string/is_valid_email_address.rs

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,31 @@ const MAX_DOMAIN_LENGTH: u32 = 255;
33
const CHARACTERS: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
44
const SYMBOLS: &str = "!#$%&'*+-/=?^_`{|}~";
55

6-
/// Returns true if email address is valid, otherwise returns false
7-
///
8-
/// A valid email address is made up of two parts, the local-part, and
9-
/// the domain.
10-
///
11-
/// The local-part may contain the following:
12-
/// - uppercase & lowercase latin letters
13-
/// - digits 0-9
14-
/// - characters !#$%&'*+-/=?^_`{|}~
15-
/// - non consecutive dots ('.') not located at start or end of local-part
16-
///
17-
/// The domain may contain the following:
18-
/// - uppercase & lowercase latin letters
19-
/// - digits 0-9
20-
/// - dash ('-') as long as not at start or end of domain
21-
///
22-
/// The local-part and domain must be separated by an '@'
23-
/// The local-part must not contain more than 64 characters
24-
/// The domain must not contain more than 255 characters
25-
pub fn is_valid_email_address(email_address: &str) -> bool {
6+
fn clear_quotes(input: &str) -> String {
7+
let mut quote_count = input.starts_with('"') as u32;
8+
let mut new_local_part: String = String::from(input.chars().next().unwrap());
9+
for i in 1..input.len() {
10+
if input.chars().nth(i).unwrap() == '"' && input.chars().nth(i - 1).unwrap() != '\\' {
11+
quote_count += 1;
12+
13+
if !new_local_part.starts_with('"') && quote_count != 1 {
14+
new_local_part.push('"');
15+
}
16+
}
17+
18+
if quote_count % 2 == 0 {
19+
new_local_part.push(input.chars().nth(i).unwrap());
20+
}
21+
}
22+
23+
new_local_part
24+
}
25+
26+
/// Follows email address rules as listed:
27+
/// https://en.wikipedia.org/wiki/Email_address#Examples
28+
pub fn is_valid_email_address(input_email_address: &str) -> bool {
29+
let email_address = clear_quotes(input_email_address);
30+
2631
let parts: Vec<String> = email_address
2732
.split('@')
2833
.map(|x| x.to_string())
@@ -42,31 +47,43 @@ pub fn is_valid_email_address(email_address: &str) -> bool {
4247
return false;
4348
}
4449

45-
// (3) validate the dots in the local part
50+
// (3) check quote dots
51+
for i in 1..local_part.len() {
52+
if local_part.chars().nth(i - 1).unwrap() == '"'
53+
&& local_part.chars().nth(i).unwrap() == '"'
54+
{
55+
let proceeding_quote = local_part.chars().nth(i + 1);
56+
if proceeding_quote.is_some() && proceeding_quote.unwrap() != '.' {
57+
return false;
58+
}
59+
}
60+
}
61+
62+
// (4) validate the dots in the local part
4663
if local_part.starts_with('.') || local_part.ends_with('.') || local_part.contains("..") {
4764
return false;
4865
}
4966

50-
// (4) check that the characters in the local part are valid
67+
// (5) check that the characters in the local part are valid
5168
for item in local_part.chars() {
52-
if !CHARACTERS.contains(item) && !SYMBOLS.contains(item) && item != '.' {
69+
if !CHARACTERS.contains(item) && !SYMBOLS.contains(item) && item != '.' && item != '"' {
5370
return false;
5471
}
5572
}
5673

57-
// (5) check that the domain contains valid characters
74+
// (6) check that the domain contains valid characters
5875
for item in domain.chars() {
59-
if !CHARACTERS.contains(item) && item != '-' && item != '.' {
76+
if !CHARACTERS.contains(item) && item != '-' && item != '.' && !"[]:".contains(item) {
6077
return false;
6178
}
6279
}
6380

64-
// (6) validate the dots in the domain
81+
// (7) validate the dots in the domain
6582
if domain.starts_with('.') || domain.ends_with('.') || domain.contains("..") {
6683
return false;
6784
}
6885

69-
// (7) validate the dashes in the domain
86+
// (8) validate the dashes in the domain
7087
if domain.starts_with('-') || domain.ends_with('-') {
7188
return false;
7289
}
@@ -91,22 +108,32 @@ mod tests {
91108
}
92109

93110
test_is_valid_email_address! {
94-
normal_email: ("[email protected]", true),
95-
email_with_dots: ("[email protected]", true),
96-
dots_with_symbols: ("[email protected]", true),
97-
dash_test: ("[email protected]", true),
98-
short_local_part: ("[email protected]", true),
99-
multiple_dash: ("[email protected]", true),
100-
extreme_valid: ("longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglon@example.com",true),
101-
extreme_invalid: ("longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglongl@example.com",false),
102-
invalid_at: ("where.is.at", false),
103-
multiple_ats: ("too@[email protected]", false),
104-
consecutive_dots: ("[email protected]", false),
105-
invalid_underscore: ("wrong@no_underscore_here", false),
106-
dash_start: ("[email protected]", false),
107-
dash_end: ("also-dont-put@here-", false),
108-
dot_start: (".not_at_start@dont", false),
109-
dot_end: ("or-at-end@here.", false),
110-
dot_start_end: ("[email protected].", false),
111+
basic: ("[email protected]", true),
112+
basic_2: ("[email protected]", true),
113+
cases: ("[email protected]", true),
114+
one_letter_local: ("[email protected]", true),
115+
long_email_subdomains: ("[email protected]", true),
116+
tags: ("[email protected]", true),
117+
slashes: ("name/[email protected]", true),
118+
no_tld: ("admin@example", true),
119+
tld: ("[email protected]", true),
120+
quotes_with_space: ("\" \"@example.org", true),
121+
quoted_double_dot: ("\"john..doe\"@example.org", true),
122+
host_route: ("[email protected]", true),
123+
quoted_non_letters: (r#""very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com"#, true),
124+
percent_symbol: ("user%[email protected]", true),
125+
local_end_symbol: ("[email protected]", true),
126+
ip_address: ("postmaster@[123.123.123.123]", true),
127+
other_ip: ("postmaster@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]", true),
128+
begin_with_underscore: ("_test@[IPv6:2001:0db8:85a3:0000:0000:8a2e:0370:7334]", true),
129+
130+
no_at: ("abc.example.com", false),
131+
multiple_ats: ("a@b@[email protected]", false),
132+
bad_local_characters: ("a\"b(c)d,e:f;g<h>i[j\\k][email protected]", false),
133+
bad_local_string: ("just\"not\"[email protected]", false),
134+
bad_backslash: ("this is\"not\\[email protected]", false),
135+
escaped_backslash: ("this\\ still\\\"not\\\\[email protected]", false),
136+
long_local_part: ("1234567890123456789012345678901234567890123456789012345678901234+x@example.com", false),
137+
domain_underscore: ("i.like.underscores@but_they_are_not_allowed_in_this_part", false),
111138
}
112139
}

0 commit comments

Comments
 (0)