Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Email validation JSON endpoint, any error is returned as `code` non-zero value with message else "ok"
package main
import (
"flag"
"fmt"
"net"
"net/http"
"net/smtp"
"regexp"
"strings"
"time"
)
var (
smptTimeout *time.Duration
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])?)*$")
)
const (
OK = iota
SMTP_ERROR
INVALID_MX_RECORD
INVALID_EMAIL_FORMAT
)
func response(code int, message string) []byte {
return []byte(fmt.Sprintf(`{ "message": "%s", "code": %d }`, message, code))
}
func split(email string) (account, host string) {
i := strings.LastIndexByte(email, '@')
account = email[:i]
host = email[i+1:]
return
}
func dialTimeout(addr string, timeout time.Duration) (*smtp.Client, error) {
conn, err := net.DialTimeout("tcp", addr, timeout)
if err != nil {
return nil, err
}
t := time.AfterFunc(timeout, func() { conn.Close() })
defer t.Stop()
host, _, _ := net.SplitHostPort(addr)
return smtp.NewClient(conn, host)
}
func checkEmail(email string) (code int, message string) {
if !emailRegexp.MatchString(email) {
return INVALID_EMAIL_FORMAT, "invalid email format"
}
_, host := split(email)
mx, err := net.LookupMX(host)
if err != nil {
return INVALID_MX_RECORD, "invalid mx record"
}
client, err := dialTimeout(fmt.Sprintf("%s:%d", mx[0].Host, 25), *smptTimeout)
if err != nil {
return SMTP_ERROR, "smtp dial error"
}
defer client.Close()
err = client.Hello("example.com")
if err != nil {
return SMTP_ERROR, "smtp hello error"
}
err = client.Mail("anyone@example.com")
if err != nil {
return SMTP_ERROR, "smtp mail error"
}
err = client.Rcpt(email)
if err != nil {
return SMTP_ERROR, "smtp reciept error"
}
return OK, "ok"
}
func handler(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
keys, ok := req.URL.Query()["email"]
if !ok || len(keys[0]) < 1 {
w.WriteHeader(http.StatusBadRequest)
w.Write(response(-1, "url param 'email' is missing"))
return
}
w.Write(response(checkEmail(keys[0])))
return
}
func main() {
smptTimeout = flag.Duration("timeout", 5*time.Second, "timeout in seconds for smtp")
port := flag.Int("port", 3001, "server http port")
flag.Parse()
http.HandleFunc("/", handler)
http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.