emailverifier

package module
v1.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 10, 2026 License: MIT Imports: 22 Imported by: 76

README

email-verifier

✉️ A Go library for email verification without sending any emails.

Build Status Godoc Coverage Status Go Report Card license

Features

  • Email Address Validation: validates if a string contains a valid email.
  • Email Verification Lookup via SMTP: performs an email verification on the passed email (catchAll detection enabled by default)
  • MX Validation: checks the DNS MX records for the given domain name
  • Misc Validation: including Free email provider check, Role account validation, Disposable emails address (DEA) validation
  • Email Reachability: checks how confident in sending an email to the address

Install

Use go get to install this package.

go get -u github.com/AfterShip/email-verifier
Supported Go versions

The three most recent Go releases, currently 1.25, 1.26 and 1.27, each covered by CI. go.mod requires the oldest of them, so an older toolchain will refuse to build this module.

Usage

Basic usage

Use Verify method to verify an email address with different dimensions

package main

import (
	"fmt"
	
	emailverifier "github.com/AfterShip/email-verifier"
)

var (
	verifier = emailverifier.NewVerifier()
)


func main() {
	email := "example@exampledomain.org"

	ret, err := verifier.Verify(email)
	if err != nil {
		fmt.Println("verify email address failed, error is: ", err)
		return
	}
	if !ret.Syntax.Valid {
		fmt.Println("email address syntax is invalid")
		return
	}

	fmt.Println("email validation result", ret)
	/*
		result is:
		{
			"email":"example@exampledomain.org",
			"disposable":false,
			"reachable":"unknown",
			"role_account":false,
			"free":false,
			"syntax":{
			"username":"example",
				"domain":"exampledomain.org",
				"valid":true
			},
			"has_mx_records":true,
			"smtp":null,
			"gravatar":null
		}
	*/
}
Email verification Lookup

Use CheckSMTP to performs an email verification lookup via SMTP.

var (
    verifier = emailverifier.
        NewVerifier().
        EnableSMTPCheck()
)

func main() {

    domain := "domain.org"
    username := "username"
    ret, err := verifier.CheckSMTP(domain, username)
    if err != nil {
        fmt.Println("check smtp failed: ", err)
        return
    }

    fmt.Println("smtp validation result: ", ret)

}

If you want to disable catchAll checking, use the DisableCatchAllCheck() switch (in effect only when SMTP verification is enabled).

 verifier = emailverifier.
        NewVerifier().
        EnableSMTPCheck().
        DisableCatchAllCheck()

Note: because most of the ISPs block outgoing SMTP requests through port 25 to prevent email spamming, the module will not perform SMTP checking by default. You can initialize the verifier with EnableSMTPCheck() to enable such capability if port 25 is usable, or use a socks proxy to connect over SMTP

Note: set FromEmail() and HelloName() before verifying at any volume. The defaults are user@example.org and localhost, and example.org is reserved by RFC 2606, so a server that validates the sender can reject the whole exchange before it ever considers the address you asked about. Rejections of this kind arrive at MAIL FROM and name the sender or the connecting host rather than the recipient, for example 550 5.7.25 Forward-confirmed reverse DNS failed or 550 5.7.1 Service unavailable, Client host [...] blocked using Spamhaus. Use a domain you control, with a PTR record for the IP you connect from.

Use a SOCKS5 proxy to verify email

Support setting a SOCKS5 proxy to verify the email, proxyURI should be in the format: socks5://user:password@127.0.0.1:1080

The protocol could be socks5, socks4 and socks4a.

var (
    verifier = emailverifier.
        NewVerifier().
        EnableSMTPCheck().
    	Proxy("socks5://user:password@127.0.0.1:1080")
)

func main() {

    domain := "domain.org"
    username := "username"
    ret, err := verifier.CheckSMTP(domain, username)
    if err != nil {
        fmt.Println("check smtp failed: ", err)
        return
    }

    fmt.Println("smtp validation result: ", ret)

}

Two things to know about the proxy:

A query string in the proxy URI is ignored. golang.org/x/net/proxy reads only the scheme, credentials and host, so a ?timeout=5s has no effect. Use ConnectTimeout() and OperationTimeout() instead.

DNS does not go through the proxy. Only the connection to the mail server does, so MX lookups still leave from the local machine. To route them through the proxy as well, dial your DNS server over TCP through it — SOCKS5 carries TCP, and Go frames DNS over a non-packet connection per RFC 7766:

socksDialer, err := proxy.SOCKS5("tcp", "127.0.0.1:1080", nil, proxy.Direct)
if err != nil {
    return err
}
verifier = emailverifier.
    NewVerifier().
    EnableSMTPCheck().
    Proxy("socks5://127.0.0.1:1080").
    Resolver(&net.Resolver{
        PreferGo: true,
        Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
            // ignore network, which may be "udp": SOCKS5 CONNECT carries TCP only
            return socksDialer.Dial("tcp", "8.8.8.8:53")
        },
    })

Each lookup opens a TCP connection through the proxy, so this costs more than plain UDP DNS.

Use a custom DNS resolver

By default, the verifier uses net.DefaultResolver (the platform's system-configured DNS resolver) for MX lookups and direct SMTP host lookups. You can override this behaviour by supplying your own *net.Resolver via Resolver(), for example to query a specific DNS server. When a proxy is configured, SMTP hostname resolution follows the proxy path rather than this resolver. MX record lookups always use this resolver, whether or not a proxy is set.

var (
    verifier = emailverifier.
        NewVerifier().
        EnableSMTPCheck().
        Resolver(&net.Resolver{
            PreferGo: true,
            Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
                d := net.Dialer{}
                return d.DialContext(ctx, network, "8.8.8.8:53")
            },
        })
)

func main() {

    domain := "domain.org"
    username := "username"
    ret, err := verifier.CheckSMTP(domain, username)
    if err != nil {
        fmt.Println("check smtp failed: ", err)
        return
    }

    fmt.Println("smtp validation result: ", ret)

}

Note: PreferGo: true is doing real work here, it is not boilerplate. MX record lookups always go through Go's own DNS client, so a custom Dial is honoured for those either way. Resolving the mail server's hostname to an IP for the TCP connection is different: without PreferGo that step may use the system (cgo) resolver, which ignores Dial entirely and quietly falls back to /etc/resolv.conf. Even with it set, /etc/hosts is still consulted before DNS, so a host listed there never reaches your resolver.

Misc Validation

To check if an email domain is disposable via IsDisposable

var (
    verifier = emailverifier.
        NewVerifier().
        EnableAutoUpdateDisposable()
)

func main() {
    domain := "domain.org"
    if verifier.IsDisposable(domain) {
        fmt.Printf("%s is a disposable domain\n", domain)
        return
    }
    fmt.Printf("%s is not a disposable domain\n", domain)
}

Note: It is possible to automatically update the disposable domains daily by initializing verifier with EnableAutoUpdateDisposable()

Suggestions for domain typo

Will check for typos in an email domain in addition to evaluating its validity. If we detect a possible typo, you will find a non-empty "suggestion" field in the validation result containing what we believe to be the correct domain. Also, you can use the SuggestDomain() method alone to check the domain for possible misspellings

func main() {
    domain := "gmai.com"
    suggestion := verifier.SuggestDomain(domain) 
    // suggestion should be `gmail.com`
    if suggestion != "" {
        fmt.Printf("domain %s is misspelled, right domain is %s. \n", domain, suggestion)
        return 
    }
    fmt.Printf("domain %s has no possible misspellings. \n", domain)
}

Note: When using the Verify() method, domain typo checking is not enabled by default, you can enable it in a verifier with EnableDomainSuggest()

For more detailed documentation, please check on godoc.org 👉 email-verifier

API

We provide a simple self-hosted API server script for reference.

The API interface is very simple. All you need to do is to send a GET request with the following URL.

The email parameter would be the target email you want to verify.

https://{your_host}/v1/{email}/verification

Similar Libraries Comparison

email-verifier trumail check-if-email-exists freemail
Features 〰️ 〰️ 〰️ 〰️
Disposable email address validation ✅ ✅, but not available in free lib ✅ ✅
Disposable address autoupdate ✅ 🤔 ❌ ❌
Free email provider check ✅ ✅, but not available in free lib ❌ ✅
Role account validation ✅ ❌ ✅ ❌
Syntax validation ✅ ✅ ✅ ❌
Email reachability ✅ ✅ ✅ ❌
DNS records validation ✅ ✅ ✅ ❌
Email deliverability ✅ ✅ ✅ ❌
Mailbox disabled ✅ ✅ ✅ ❌
Full inbox ✅ ✅ ✅ ❌
Host exists ✅ ✅ ✅ ❌
Catch-all ✅ ✅ ✅ ❌
Gravatar ✅ ✅, but not available in free lib ❌ ❌
Typo check ✅ ✅, but not available in free lib ❌ ❌
Use proxy to connect over SMTP ✅ ❌ ✅ ❌
Honeyport dection 🔜 ❌ ❌ ❌
Bounce email check 🔜 ❌ ❌ ❌
Tech 〰️ 〰️ 〰️ 〰️
Provide API ✅ ✅ ✅ ❌
Free API ✅ ❌ ❌ ❌
Language Go Go Rust JavaScript
Active maintain ✅ ❌ ✅ ✅
High Performance ✅ ❌ ✅ ✅

FAQ

The library hangs/takes a long time after 30 seconds when performing email verification lookup via SMTP

Most ISPs block outgoing SMTP requests through port 25 to prevent email spamming. email-verifier needs to have this port open to make a connection to the email's SMTP server. With the port being blocked, it is not possible to perform such checking, and it will instead hang until timeout error. Unfortunately, there is no easy workaround for this issue.

For more information, you may also visit this StackOverflow thread.

The output shows "connection refused" in the smtp.error field.

This error can also be due to SMTP ports being blocked by the ISP, see the above answer.

What does reachable: "unknown" means

This means that the server does not allow real-time verification of an email right now, or the email provider is a catch-all email server.

Credits

Contributing

For details on contributing to this repository, see the contributing guide.

License

This package is licensed under MIT license. See LICENSE for details.

Documentation

Index

Constants

View Source
const (
	// Standard Errors
	ErrTimeout           = "The connection to the mail server has timed out"
	ErrNoSuchHost        = "Mail server does not exist"
	ErrServerUnavailable = "Mail server is unavailable"
	ErrBlocked           = "Blocked by mail server"

	// RCPT Errors
	ErrTryAgainLater           = "Try again later"
	ErrFullInbox               = "Recipient out of disk space"
	ErrTooManyRCPT             = "Too many recipients"
	ErrNoRelay                 = "Not an open relay"
	ErrMailboxBusy             = "Mailbox busy"
	ErrExceededMessagingLimits = "Messaging limits have been exceeded"
	ErrNotAllowed              = "Not Allowed"
	ErrNeedMAILBeforeRCPT      = "Need MAIL before RCPT"
	ErrRCPTHasMoved            = "Recipient has moved"
)

Variables

This section is empty.

Functions

func GenerateRandomEmail

func GenerateRandomEmail(domain string) string

GenerateRandomEmail generates a random email address using the domain passed. Used primarily for checking the existence of a catch-all address

func IsAddressValid

func IsAddressValid(email string) bool

IsAddressValid checks if email address is formatted correctly by using regex

Types

type Gravatar added in v1.0.1

type Gravatar struct {
	HasGravatar bool   `json:"has_gravatar"` // whether has gravatar
	GravatarUrl string `json:"gravatar_url"` // gravatar url
}

Gravatar is detail about the Gravatar

type LookupError

type LookupError struct {
	Message string `json:"message" xml:"message"`
	Details string `json:"details" xml:"details"`
	// contains filtered or unexported fields
}

LookupError is an MX dns records lookup error

func ParseSMTPError

func ParseSMTPError(err error) *LookupError

ParseSMTPError receives an MX Servers response message and generates the corresponding MX error.

A non-nil err always yields a non-nil result: an error we cannot classify is reported verbatim rather than discarded. Returning nil here would hand the caller a non-nil error interface wrapping a nil *LookupError, whose Error method then panics.

func (*LookupError) Error

func (e *LookupError) Error() string

func (*LookupError) Unwrap added in v1.5.0

func (e *LookupError) Unwrap() error

Unwrap returns the error this LookupError was derived from, if any.

type Mx

type Mx struct {
	HasMXRecord bool      // whether has 1 or more MX record
	Records     []*net.MX // represent DNS MX records
}

Mx is detail about the Mx host

type Result

type Result struct {
	Email        string    `json:"email"`          // passed email address
	Reachable    string    `json:"reachable"`      // an enumeration to describe whether the recipient address is real
	Syntax       Syntax    `json:"syntax"`         // details about the email address syntax
	SMTP         *SMTP     `json:"smtp"`           // details about the SMTP response of the email
	Gravatar     *Gravatar `json:"gravatar"`       // whether or not have gravatar for the email
	Suggestion   string    `json:"suggestion"`     // domain suggestion when domain is misspelled
	Disposable   bool      `json:"disposable"`     // is this a DEA (disposable email address)
	RoleAccount  bool      `json:"role_account"`   // is account a role-based account
	Free         bool      `json:"free"`           // is domain a free email domain
	HasMxRecords bool      `json:"has_mx_records"` // whether or not MX-Records for the domain
}

Result is the result of Email Verification

type SMTP

type SMTP struct {
	HostExists  bool `json:"host_exists"` // is the host exists?
	FullInbox   bool `json:"full_inbox"`  // is the email account's inbox full?
	CatchAll    bool `json:"catch_all"`   // does the domain have a catch-all email address?
	Deliverable bool `json:"deliverable"` // can send an email to the email server?
	Disabled    bool `json:"disabled"`    // is the email blocked or disabled by the provider?
}

SMTP stores all information for SMTP verification lookup

type Syntax

type Syntax struct {
	Username string `json:"username"`
	Domain   string `json:"domain"`
	Valid    bool   `json:"valid"`
}

Syntax stores all information about an email Syntax

type Verifier

type Verifier struct {
	// contains filtered or unexported fields
}

Verifier is an email verifier. Create one by calling NewVerifier

func NewVerifier

func NewVerifier() *Verifier

NewVerifier creates a new email verifier

func (*Verifier) AddDisposableDomains added in v1.2.0

func (v *Verifier) AddDisposableDomains(domains []string) *Verifier

AddDisposableDomains adds additional domains as disposable domains.

func (*Verifier) CheckGravatar added in v1.0.1

func (v *Verifier) CheckGravatar(email string) (*Gravatar, error)

CheckGravatar will return the Gravatar records for the given email.

func (*Verifier) CheckMX

func (v *Verifier) CheckMX(domain string) (*Mx, error)

CheckMX will return the DNS MX records for the given domain name sorted by preference.

func (*Verifier) CheckSMTP

func (v *Verifier) CheckSMTP(domain, username string) (*SMTP, error)

CheckSMTP performs an email verification on the passed domain via SMTP

  • the domain is the passed email domain
  • username is used to check the deliverability of specific email address,

if server is catch-all server, username will not be checked

func (*Verifier) ConnectTimeout added in v1.4.1

func (v *Verifier) ConnectTimeout(timeout time.Duration) *Verifier

ConnectTimeout sets the timeout for establishing connections.

func (*Verifier) DisableAPIVerifier added in v1.4.0

func (v *Verifier) DisableAPIVerifier(name string)

func (*Verifier) DisableAutoUpdateDisposable

func (v *Verifier) DisableAutoUpdateDisposable() *Verifier

DisableAutoUpdateDisposable stops previously started schedule job

func (*Verifier) DisableCatchAllCheck added in v1.3.3

func (v *Verifier) DisableCatchAllCheck() *Verifier

DisableCatchAllCheck disables catchAll check by smtp

func (*Verifier) DisableDomainSuggest added in v1.0.3

func (v *Verifier) DisableDomainSuggest() *Verifier

DisableDomainSuggest will not suggest anything

func (*Verifier) DisableGravatarCheck added in v1.0.1

func (v *Verifier) DisableGravatarCheck() *Verifier

DisableGravatarCheck disables check gravatar,

func (*Verifier) DisableSMTPCheck

func (v *Verifier) DisableSMTPCheck() *Verifier

DisableSMTPCheck disables check email by smtp

func (*Verifier) EnableAPIVerifier added in v1.4.0

func (v *Verifier) EnableAPIVerifier(name string) error

EnableAPIVerifier activates an API-based existence check for the given vendor. ** Please know ** that this is a tricky way (but relatively stable) to check if target vendor's email exists. If you use this feature in a production environment, please ensure that you have sufficient backup measures in place, as this may encounter rate limiting or other API issues.

There are currently no built-in vendors: the Yahoo verifier was removed once its endpoint stopped existing (see https://github.com/AfterShip/email-verifier/issues/195), following the same fate as the Gmail verifier removed in #113. This remains an extension point; contributions adding a working vendor are welcome.

func (*Verifier) EnableAutoUpdateDisposable

func (v *Verifier) EnableAutoUpdateDisposable() *Verifier

EnableAutoUpdateDisposable enables update disposable domains automatically

func (*Verifier) EnableCatchAllCheck added in v1.3.3

func (v *Verifier) EnableCatchAllCheck() *Verifier

EnableCatchAllCheck enables catchAll check by smtp for most ISPs block outgoing catchAll requests through port 25, to prevent spam, we don't check catchAll by default

func (*Verifier) EnableDomainSuggest added in v1.0.3

func (v *Verifier) EnableDomainSuggest() *Verifier

EnableDomainSuggest will suggest a most similar correct domain when domain misspelled

func (*Verifier) EnableGravatarCheck added in v1.0.1

func (v *Verifier) EnableGravatarCheck() *Verifier

EnableGravatarCheck enables check gravatar, we don't check gravatar by default

func (*Verifier) EnableSMTPCheck

func (v *Verifier) EnableSMTPCheck() *Verifier

EnableSMTPCheck enables check email by smtp, for most ISPs block outgoing SMTP requests through port 25, to prevent spam, we don't check smtp by default

func (*Verifier) FromEmail

func (v *Verifier) FromEmail(email string) *Verifier

FromEmail sets the emails to use in the `MAIL FROM:` smtp command

func (*Verifier) HelloName

func (v *Verifier) HelloName(domain string) *Verifier

HelloName sets the name to use in the `EHLO:` SMTP command

func (*Verifier) IsDisposable

func (v *Verifier) IsDisposable(domain string) bool

IsDisposable checks if domain is a disposable domain

func (*Verifier) IsFreeDomain

func (v *Verifier) IsFreeDomain(domain string) bool

IsFreeDomain checks if domain is a free domain

func (*Verifier) IsRoleAccount

func (v *Verifier) IsRoleAccount(username string) bool

IsRoleAccount checks if username is a role-based account

func (*Verifier) OperationTimeout added in v1.4.1

func (v *Verifier) OperationTimeout(timeout time.Duration) *Verifier

OperationTimeout sets the timeout for SMTP operations (e.g., EHLO, MAIL FROM, etc.).

func (*Verifier) ParseAddress

func (v *Verifier) ParseAddress(email string) Syntax

ParseAddress attempts to parse an email address and return it in the form of an Syntax

func (*Verifier) Proxy added in v1.3.0

func (v *Verifier) Proxy(proxyURI string) *Verifier

Proxy sets a SOCKS5 proxy to verify the email, proxyURI should be in the format: "socks5://user:password@127.0.0.1:1080". The protocol could be socks5, socks4 and socks4a.

Only the scheme, credentials and host are read; a query string is ignored, so a "?timeout=5s" has no effect. Use ConnectTimeout and OperationTimeout.

The proxy carries the connection to the mail server, not DNS: MX lookups still go out from the local machine. See Resolver for routing those through the proxy too.

func (*Verifier) Resolver added in v1.5.0

func (v *Verifier) Resolver(resolver *net.Resolver) *Verifier

Resolver sets a custom DNS resolver to use for MX and SMTP host lookups, allowing users to configure custom DNS servers instead of relying on the system's default resolver (e.g. /etc/resolv.conf). Passing nil restores the default resolver (net.DefaultResolver).

func (*Verifier) SuggestDomain added in v1.0.3

func (v *Verifier) SuggestDomain(domain string) string

SuggestDomain checks if domain has a typo and suggests a similar correct domain from metadata, returns a suggestion

func (*Verifier) Verify

func (v *Verifier) Verify(email string) (*Result, error)

Verify performs address, misc, mx and smtp checks

Directories

Path Synopsis
cmd
apiserver command
build_metadata command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL