-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathemail_validator.go
More file actions
executable file
·100 lines (80 loc) · 2.46 KB
/
email_validator.go
File metadata and controls
executable file
·100 lines (80 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package campid
import (
"errors"
"net"
"regexp"
"strings"
)
var (
emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
)
var (
//ErrInvalidFormat returns when email's format is invalid
ErrInvalidFormat = errors.New("invalid format")
//ErrUnresolvableHost returns when validator couldn't resolve email's host
ErrUnresolvableHost = errors.New("unresolvable host")
userRegexp = regexp.MustCompile("^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+$")
hostRegexp = regexp.MustCompile("^[^\\s]+\\.[^\\s]+$")
// As per RFC 5332 secion 3.2.3: https://tools.ietf.org/html/rfc5322#section-3.2.3
// Dots are not allowed in the beginning, end or in occurances of more than 1 in the email address
userDotRegexp = regexp.MustCompile("(^[.]{1})|([.]{1}$)|([.]{2,})")
)
// ValidateEmail checks format of a given email and resolves its host name.
func ValidateEmail(email string) error {
if len(email) < 6 || len(email) > 254 {
return ErrInvalidFormat
}
at := strings.LastIndex(email, "@")
if at <= 0 || at > len(email)-3 {
return ErrInvalidFormat
}
user := email[:at]
host := email[at+1:]
if len(user) > 64 {
return ErrInvalidFormat
}
if userDotRegexp.MatchString(user) || !userRegexp.MatchString(user) || !hostRegexp.MatchString(host) {
return ErrInvalidFormat
}
switch host {
case "localhost", "example.com":
return nil
}
if _, err := net.LookupMX(host); err != nil {
if _, err := net.LookupIP(host); err != nil {
// Only fail if both MX and A records are missing - any of the
// two is enough for an email to be deliverable
return ErrUnresolvableHost
}
}
return nil
}
// ValidateEmailFast checks format of a given email.
func ValidateEmailFast(email string) error {
if len(email) < 6 || len(email) > 254 {
return ErrInvalidFormat
}
at := strings.LastIndex(email, "@")
if at <= 0 || at > len(email)-3 {
return ErrInvalidFormat
}
user := email[:at]
host := email[at+1:]
if len(user) > 64 {
return ErrInvalidFormat
}
if userDotRegexp.MatchString(user) || !userRegexp.MatchString(user) || !hostRegexp.MatchString(host) {
return ErrInvalidFormat
}
return nil
}
// NormalizeEmail normalizes email address.
func NormalizeEmail(email string) string {
// Trim whitespaces.
email = strings.TrimSpace(email)
// Trim extra dot in hostname.
email = strings.TrimRight(email, ".")
// Lowercase.
email = strings.ToLower(email)
return email
}