-
Notifications
You must be signed in to change notification settings - Fork 0
/
email.go
80 lines (61 loc) · 1.9 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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
package system
import (
"errors"
"fmt"
"net/mail"
"regexp"
"strings"
"unicode/utf8"
"github.com/polyscone/tofu/human"
)
const emailMaxLength = 100
var (
invalidEmailChars = regexp.MustCompile(`[^a-zA-Z0-9+.@_~\-]`)
validEmailSeq = regexp.MustCompile(`^[a-zA-Z0-9+._~\-]+@[a-zA-Z0-9+._~\-]+(\.[a-zA-Z0-9+._~\-]+)+$`)
)
type Email string
func NewEmail(email string) (Email, error) {
if strings.TrimSpace(email) == "" {
return "", errors.New("cannot be empty")
}
if strings.ContainsAny(email, " \t\r\n") {
return "", errors.New("cannot contain whitespace")
}
if strings.ContainsAny(email, `"'`) {
return "", errors.New("cannot contain quotes")
}
if rc := utf8.RuneCountInString(email); rc > emailMaxLength {
return "", fmt.Errorf("cannot be a over %v characters in length", emailMaxLength)
}
addr, err := mail.ParseAddress(email)
if err != nil {
email = strings.TrimSpace(email)
msg := strings.TrimPrefix(strings.ToLower(err.Error()), "mail: ")
switch {
case strings.Contains(msg, "missing '@'"):
return "", errors.New("missing the @ sign")
case strings.HasPrefix(email, "@"):
return "", errors.New("missing part before the @ sign")
case strings.HasSuffix(email, "@"):
return "", errors.New("missing part after the @ sign")
}
return "", errors.New(msg)
}
if addr.Name != "" {
return "", errors.New("cannot not include a name")
}
if matches := invalidEmailChars.FindAllString(addr.Address, -1); len(matches) != 0 {
return "", fmt.Errorf("cannot contain: %v", human.OrList(matches))
}
if !validEmailSeq.MatchString(addr.Address) {
_, end, _ := strings.Cut(addr.Address, "@")
if !strings.Contains(end, ".") {
return "", errors.New("missing top-level domain, e.g. .com, .co.uk, etc.")
}
return "", errors.New("must be an email address, e.g. email@example.com")
}
return Email(addr.Address), nil
}
func (e Email) String() string {
return string(e)
}