Validating an Email Address

· 488 words · 3 minutes read

Validating email addresses, like many thing, are one of those things you can put any amount of effort you want into.

The solutions range from nice’n’quick, by using regex to check the email address is formatted correctly - through to complicated, by actually trying to interface with the remote server. There are also some middle grounds available in between, like checking the top level domain has a valid MX record and detecting temporary email addresses (if these aren’t wanted). (Are there any ideas I’ve missed?)

The problem has been around since email addresses have existed.

The one sure way is to send an email to the address and have the user click on a link to confirm. But this post will look at the quicker pre-email checks first.

The Simple Version: Regex

Based on the regex by W3C, this code checks the structure of the email address.

 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
package main

import (
	"fmt"
	"regexp"
)

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

func main() {
	// Valid example
	e := "test@golangcode.com"
	if isEmailValid(e) {
		fmt.Println(e + " is a valid email")
	}

	// Invalid example
	if !isEmailValid("just text") {
		fmt.Println("not a valid email")
	}
}

// isEmailValid checks if the email provided passes the required structure and length.
func isEmailValid(e string) bool {
	if len(e) < 3 && len(e) > 254 {
		return false
	}
	return emailRegex.MatchString(e)
}

check email is valid using regex

Slightly better solution: Regex + MX Lookup

In this example, we combine the quick speed of a regex check of the email address with the slightly more dependable lookup of an MX record. This means if the domain part of the email doesn’t exist, or the domain doesn’t accept emails it will be marked as invalid.

As part of the net package we can call on LookupMX to do this extra lookup for us.

 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
package main

import (
	"fmt"
	"net"
	"regexp"
	"strings"
)

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

func main() {
	// Made-up domain
	if e := "test@golangcode-example.com"; !isEmailValid(e) {
		fmt.Println(e + " is not a valid email")
	}
	// Real domain
	if e := "test@google.com"; !isEmailValid(e) {
		fmt.Println(e + " not a valid email")
	}
}

// isEmailValid checks if the email provided passes the required structure
// and length test. It also checks the domain has a valid MX record.
func isEmailValid(e string) bool {
	if len(e) < 3 && len(e) > 254 {
		return false
	}
	if !emailRegex.MatchString(e) {
		return false
	}
	parts := strings.Split(e, "@")
	mx, err := net.LookupMX(parts[1])
	if err != nil || len(mx) == 0 {
		return false
	}
	return true
}

check an email is valid with mx lookup

Image of Author Edd Turtle

Author:  Edd Turtle

Edd is the Lead Developer at Hoowla, a prop-tech startup, where he spends much of his time working on production-ready Go and PHP code. He loves coding, but also enjoys cycling and camping in his spare time.

See something which isn't right? You can contribute to this page on GitHub or just let us know in the comments below - Thanks for reading!