如何在 Go 中验证电子邮件地址

How to validate an email address in Go

我查看了 Whosebug,但找不到任何问题可以回答 如何使用 Go 语言验证电子邮件

经过一番研究,我想通了,按我的需要解决了。

我有这个 regexGo 函数,工作正常:

import (
    "fmt"
    "regexp"
)

func main() {
    fmt.Println(isEmailValid("test44@gmail.com")) // true
    fmt.Println(isEmailValid("test$@gmail.com")) // true -- expected "false" 
}


// isEmailValid checks if the email provided is valid by regex.
func isEmailValid(e string) bool {
    emailRegex := 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])?)*$")
    return emailRegex.MatchString(e)
}

问题是它接受我不想要的特殊字符。我尝试使用其他语言的“正则表达式”表达式,但它在调试中抛出错误 "unknown escape"

谁能给我一个好的正则表达式或任何适用于 GoLang 的快速解决方案 (pkg)?

标准库内置了电子邮件解析和验证,只需使用:mail.ParseAddress().

一个简单的“有效”测试:

func valid(email string) bool {
    _, err := mail.ParseAddress(email)
    return err == nil
}

正在测试:

for _, email := range []string{
    "good@exmaple.com",
    "bad-example",
} {
    fmt.Printf("%18s valid: %t\n", email, valid(email))
}

哪些输出(在 Go Playground 上尝试):

  good@exmaple.com valid: true
       bad-example valid: false

The above approach from @icza is nice, however, if we use it in login/signup form validation, many people will enter a partial or incorrect email address, which will create a bunch of invalid records in production. Furthermore, who knows we might get killed because of that.

Therefore, I went to the regex solution to validate standard emails:

Here is the code:

func isEmailValid(e string) bool {
    emailRegex := regexp.MustCompile(`^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$`)
    return emailRegex.MatchString(e)
}

Test Cases:

fmt.Println(isEmailValid("test44@gmail.com"))         // true 
fmt.Println(isEmailValid("bad-email"))               // false
fmt.Println(isEmailValid("test44$@gmail.com"))      // false
fmt.Println(isEmailValid("test-email.com"))        // false
fmt.Println(isEmailValid("test+email@test.com"))  // true

方法实现示例:

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])?)*$")

这与我创建结构的包在同一个包中

type EmailInputRegistration struct {
    Email           string
}

然后处理错误:

func (in EmailInputRegistration) Validate() error {
    if !emailRegexp.MatchString(in.Email) {
        return fmt.Errorf("%w: email invalid", ErrValidation)
    }
    //any other exception handling...

    return nil
}

理想情况下,应重构此 EmailInputRegistration 以包含注册所需的所有数据,例如电子邮件、用户、密码等。

由于我发现正则表达式难以阅读,所以我更喜欢可读的无聊代码。例如:

// Accepts at least the x@y.zz pattern.
func isEmailAddress(v string) bool {
    if v == "" {
        return false
    }
    if containsWhitespace(v) {
        return false
    }

    iAt := strings.IndexByte(v, '@')
    if iAt == -1 {
        return false
    }

    localPart := v[:iAt]
    if localPart == "" {
        return false
    }

    domain := v[iAt+1:]
    if domain == "" {
        return false
    }

    iDot := strings.IndexByte(domain, '.')
    if iDot == -1 || iDot == 0 || iDot == len(domain)-1 {
        return false
    }

    if strings.Index(domain, "..") != -1 {
        return false
    }

    iTLD := strings.LastIndexByte(domain, '.')
    return 2 <= len([]rune(domain[iTLD+1:]))
}

func containsWhitespace(v string) bool {
    for _, r := range v {
        if unicode.IsSpace(r) {
            return true
        }
    }
    return false
}