This repository has been archived by the owner on Apr 4, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathemail.go
60 lines (51 loc) · 1.57 KB
/
email.go
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
package input
import (
"errors"
"fmt"
"golang.org/x/net/idna"
"regexp"
"strings"
)
var (
// Invalid e-mail address.
ErrInvalidEmail = errors.New("invalid e-mail address")
// E-mail address user part pattern.
emailUserPartPattern = regexp.MustCompile(`^[-!#$%&'*+/=?^_` + "`" + `{}|~0-9A-Za-z]+(\.[-!#$%&'*+/=?^_` + "`" + `{}|~0-9A-Za-z]+)*$`)
// E-mail address domain part pattern.
emailDomainPartPattern = regexp.MustCompile(`^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+([a-zA-Z0-9\-]{2,63})$`)
)
// Parse e-mail.
//
// Lower-cases the entire e-mail address and normalizes the domain part with
// IDNA encoding. This method does not allow IP address domain parts, nor
// quoted user parts.
func ParseEmail(in string) (out string, err error) {
// First, attempt to split the e-mail address into user and domain parts.
atIndex := strings.IndexByte(in, '@')
if atIndex == -1 {
err = ErrInvalidEmail
return
}
userPart := strings.TrimSpace(in[:atIndex])
domainPart := strings.TrimSpace(in[atIndex+1:])
// Validate the user part.
if !emailUserPartPattern.MatchString(userPart) {
err = ErrInvalidEmail
return
}
// Validate the domain part.
if !emailDomainPartPattern.MatchString(domainPart) {
// Try for possible IDN domain-part.
var idnaErr error
if domainPart, idnaErr = idna.ToASCII(domainPart); idnaErr == nil {
if !emailDomainPartPattern.MatchString(domainPart) {
err = ErrInvalidEmail
return
}
} else {
err = ErrInvalidEmail
return
}
}
return fmt.Sprintf("%s@%s", strings.ToLower(userPart), strings.ToLower(domainPart)), nil
}