this repo has no description
1pub const MAX_EMAIL_LENGTH: usize = 254;
2pub const MAX_LOCAL_PART_LENGTH: usize = 64;
3pub const MAX_DOMAIN_LENGTH: usize = 253;
4pub const MAX_DOMAIN_LABEL_LENGTH: usize = 63;
5
6const EMAIL_LOCAL_SPECIAL_CHARS: &str = ".!#$%&'*+/=?^_`{|}~-";
7
8pub fn is_valid_email(email: &str) -> bool {
9 let email = email.trim();
10
11 if email.is_empty() || email.len() > MAX_EMAIL_LENGTH {
12 return false;
13 }
14
15 let parts: Vec<&str> = email.rsplitn(2, '@').collect();
16 if parts.len() != 2 {
17 return false;
18 }
19
20 let domain = parts[0];
21 let local = parts[1];
22
23 if local.is_empty() || local.len() > MAX_LOCAL_PART_LENGTH {
24 return false;
25 }
26
27 if local.starts_with('.') || local.ends_with('.') {
28 return false;
29 }
30
31 if local.contains("..") {
32 return false;
33 }
34
35 for c in local.chars() {
36 if !c.is_ascii_alphanumeric() && !EMAIL_LOCAL_SPECIAL_CHARS.contains(c) {
37 return false;
38 }
39 }
40
41 if domain.is_empty() || domain.len() > MAX_DOMAIN_LENGTH {
42 return false;
43 }
44
45 if !domain.contains('.') {
46 return false;
47 }
48
49 for label in domain.split('.') {
50 if label.is_empty() || label.len() > MAX_DOMAIN_LABEL_LENGTH {
51 return false;
52 }
53
54 if label.starts_with('-') || label.ends_with('-') {
55 return false;
56 }
57
58 for c in label.chars() {
59 if !c.is_ascii_alphanumeric() && c != '-' {
60 return false;
61 }
62 }
63 }
64
65 true
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn test_valid_emails() {
74 assert!(is_valid_email("user@example.com"));
75 assert!(is_valid_email("user.name@example.com"));
76 assert!(is_valid_email("user+tag@example.com"));
77 assert!(is_valid_email("user@sub.example.com"));
78 assert!(is_valid_email("USER@EXAMPLE.COM"));
79 assert!(is_valid_email("user123@example123.com"));
80 assert!(is_valid_email("a@b.co"));
81 }
82
83 #[test]
84 fn test_invalid_emails() {
85 assert!(!is_valid_email(""));
86 assert!(!is_valid_email("user"));
87 assert!(!is_valid_email("user@"));
88 assert!(!is_valid_email("@example.com"));
89 assert!(!is_valid_email("user@example"));
90 assert!(!is_valid_email("user@@example.com"));
91 assert!(!is_valid_email("user@.example.com"));
92 assert!(!is_valid_email("user@example..com"));
93 assert!(!is_valid_email(".user@example.com"));
94 assert!(!is_valid_email("user.@example.com"));
95 assert!(!is_valid_email("user..name@example.com"));
96 assert!(!is_valid_email("user@-example.com"));
97 assert!(!is_valid_email("user@example-.com"));
98 }
99
100 #[test]
101 fn test_trimmed_whitespace() {
102 assert!(is_valid_email(" user@example.com "));
103 }
104}