isValid
函数用于验证和规范化电子邮件地址。如果电子邮件包含非ASCII字符,它会将其转换为Punycode。然后,该函数会检查电子邮件是否符合有效电子邮件地址的规定,从而支持任何语言。
然后,可以使用
idna.ToUnicode
函数将其转换回原始语言。这种可逆性确保国际化域名和电子邮件地址可以以标准化的形式存储和处理,同时以可读和可理解的格式呈现给用户。
我认为这是在该网站上找到的用于电子邮件检查的最佳选择,毫无疑问。
package main
import (
"fmt"
"strings"
"golang.org/x/net/idna"
)
func isValid(email string) interface{} {
if len(email) > 320 {
return fmt.Errorf("email length exceeds 320 characters")
}
parts := strings.Split(strings.ToLower(email), "@")
if len(parts) != 2 {
return fmt.Errorf("email must contain a single '@' character")
}
localPart, domainPart := parts[0], parts[1]
if len(localPart) == 0 || len(domainPart) == 0 {
return fmt.Errorf("local or domain part cannot be empty in the email")
}
prevChar := rune(0)
for _, char := range localPart {
if strings.ContainsRune("!#$%&'*+-/=?^_`{|}~.", char) {
if char == prevChar && char != '-' {
return fmt.Errorf("consecutive special characters '%c' are not allowed in the local part", char)
}
}
prevChar = char
}
if strings.ContainsAny(email, " ") {
return fmt.Errorf("spaces are not allowed in the email")
}
if len(localPart) > 64 || len(domainPart) > 255 {
return fmt.Errorf("local part or domain part length exceeds the limit in the email")
}
asciiDomain, err := idna.ToASCII(domainPart)
if err != nil {
return fmt.Errorf("failed to convert domain to ASCII: %s", err)
}
asciiLocal, err := idna.ToASCII(localPart)
if err != nil {
return fmt.Errorf("failed to convert local part to ASCII: %s", err)
}
domainLabels := strings.Split(asciiDomain, ".")
for i, label := range domainLabels {
if !strings.ContainsAny("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", string(label[0])) ||
!strings.ContainsAny("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", string(label[len(label)-1])) {
return fmt.Errorf("domain labels must not start or end with special characters in the email")
}
if len(label) > 63 {
return fmt.Errorf("domain label length exceeds the limit in the email")
}
if i == len(domainLabels)-1 && !strings.HasPrefix(label, "xn--") {
decodedTLD, err := idna.ToUnicode(label)
if err != nil {
return fmt.Errorf("failed to decode TLD: %s", err)
}
isAlpha := true
for _, ch := range decodedTLD {
if (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z') {
isAlpha = false
break
}
}
if !isAlpha {
return fmt.Errorf("TLD must be alphabetic in the email")
}
}
}
return fmt.Sprintf("%s@%s", asciiLocal, asciiDomain)
}
func main() {
fmt.Println(isValid("test@example.com"))
fmt.Println(isValid("tést@example.com"))
fmt.Println(isValid("test@xn--fsqu00a.xn--0zwm56d"))
fmt.Println(isValid("test@例子.测试"))
fmt.Println(isValid("tést@例子.测试"))
fmt.Println(isValid("тест@пример.ру"))
fmt.Println(isValid("اختبار@مثال.اختبار"))
fmt.Println(isValid("בדיקה@דוגמה.בדיקה"))
fmt.Println(isValid("xn--e1aybc@xn--80akhbyknj4f.xn--p1ai"))
fmt.Println(isValid("測試@例子.測試"))
fmt.Println(isValid("テスト@例.テスト"))
fmt.Println(isValid("테스트@예시.테스트"))
fmt.Println(isValid("test..test@example.com"))
fmt.Println(isValid(".test@example.com"))
fmt.Println(isValid("test.@example.com"))
fmt.Println(isValid("test test@example.com"))
fmt.Println(isValid("@example.com"))
fmt.Println(isValid("test@"))
fmt.Println(isValid(""))
fmt.Println(isValid(strings.Repeat("a", 320) + "@example.com"))
}