Validate email address in Go
development golang emailFirstly, based on the RFC 3696 Errata 1690, a valid email address has a maximum of 254 characters. Here is the relevant snippet from the RFC:
A valid email address has a maximum of 64 characters in the “local part” (before the “@") and a maximum of 255 characters in the domain part (after the “@") for a total length of 320 characters. However, there is a restriction in RFC 2821 on the length of an address in MAIL and RCPT commands of 254 characters.
Secondly, W3C has provided recommendation on the valid email address syntax. It also provides a regular expression that can be used to validate the syntax of the email address. Here is the relevant regex snippet from the document linked earlier:
/^[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])?)*$/
Finally, check for the existance of the MX record for the domain part of the email address. We can lookup MX record in Go using the `net` package.
So let’s combine these into a utility function in Go.
// filename: validate.go
package main
import (
"net"
"regexp"
"strings"
)
func validEmail(id string) bool {
if len(id) > maxEmailLength {
return false
}
if !emailRegex.MatchString(id) {
return false
}
domain := strings.Split(id, "@")[1]
if mx, errLookup := net.LookupMX(domain); errLookup != nil || len(mx) == 0 {
return false
}
return true
}
const maxEmailLength = 254
var 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])?)*$")
// filename: validate_test.go
package main
import (
"fmt"
"testing"
)
// TestEmailValidity is the unit test to test validEmail function.
func TestEmailValidity(t *testing.T) {
var tests = []struct {
email string
want bool
}{
{email: "test@gmail.com", want: true},
{email: "test@notgmail.com", want: false},
{email: "test@", want: false},
{email: "@gmail.com", want: false},
}
for _, td := range tests {
testname := fmt.Sprintf("when testing email id `%s`", td.email)
t.Run(testname, func(t *testing.T) {
ok := validEmail(td.email)
if ok != td.want {
t.Errorf("got %t, want %t", ok, td.want)
}
})
}
}
# result of the unit test
➜ go test -v
=== RUN TestEmailValidity
=== RUN TestEmailValidity/when_testing_email_id_`test@gmail.com`
=== RUN TestEmailValidity/when_testing_email_id_`test@notgmail.com`
=== RUN TestEmailValidity/when_testing_email_id_`test@`
=== RUN TestEmailValidity/when_testing_email_id_`@gmail.com`
--- PASS: TestEmailValidity (3.82s)
--- PASS: TestEmailValidity/when_testing_email_id_`test@gmail.com` (0.26s)
--- PASS: TestEmailValidity/when_testing_email_id_`test@notgmail.com` (3.56s)
--- PASS: TestEmailValidity/when_testing_email_id_`test@` (0.00s)
--- PASS: TestEmailValidity/when_testing_email_id_`@gmail.com` (0.00s)
PASS
ok go.imgur.com/validate-email 5.107s
References
- https://www.rfc-editor.org/errata_search.php?rfc=3696&eid=1690
- https://www.w3.org/TR/2016/REC-html51-20161101/sec-forms.html#valid-e-mail-address
- https://pkg.go.dev/net#LookupMX
In case you would like to get notified about more articles like this, please subscribe to my substack.
Related Posts
Delete Queues in AWS SQS using GoReceive Messages from AWS SQS using Go
Listing Files in AWS S3 using Go
Validate Tor IP Address in Go
Strings in Go