AfterShip / email-verifier

:white_check_mark: A Go library for email verification without sending any emails.
MIT License
1.18k stars 149 forks source link

Update Verify() with goroutine to speed up the request and some minor changes #121

Open daison12006013 opened 3 months ago

daison12006013 commented 3 months ago

Updates

In the meantime, if someone would like to incorporate this on their code, you may copy below

Source Code ```go package email_checker import ( "context" "time" emailVerifier "github.com/AfterShip/email-verifier" ) func GetEmailInformation(email string) (EmailInformation, error) { verification, err := NewVerifier().Verify(email) if err != nil { return EmailInformation{}, err } return EmailInformation{ IsValidFormat: verification.Syntax.Valid, Result: *verification, }, nil } var ( reachableYes = "yes" reachableNo = "no" reachableUnknown = "unknown" smtpCheckEnabled bool = true catchAllCheckEnabled bool = true gravatarCheckEnabled bool = true domainSuggestEnabled bool = true ) type Verifier struct { *emailVerifier.Verifier } type EmailInformation struct { IsValidFormat bool `json:"is_valid_format"` emailVerifier.Result } func NewVerifier() *Verifier { verifier := &Verifier{emailVerifier.NewVerifier()} verifier.EnableAutoUpdateDisposable() if smtpCheckEnabled { verifier.EnableSMTPCheck() } if catchAllCheckEnabled { verifier.EnableCatchAllCheck() } if gravatarCheckEnabled { verifier.EnableGravatarCheck() } if domainSuggestEnabled { verifier.EnableDomainSuggest() } return verifier } func (v *Verifier) Verify(email string) (*emailVerifier.Result, error) { ret := emailVerifier.Result{ Email: email, Reachable: reachableUnknown, } syntax := v.ParseAddress(email) ret.Syntax = syntax if !syntax.Valid { return &ret, nil } ret.Free = v.IsFreeDomain(syntax.Domain) ret.RoleAccount = v.IsRoleAccount(syntax.Username) ret.Disposable = v.IsDisposable(syntax.Domain) // If the domain name is disposable, mx and smtp are not checked. if ret.Disposable { return &ret, nil } ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) defer cancel() mxCh := make(chan *emailVerifier.Mx) smtpCh := make(chan *emailVerifier.SMTP) errCh := make(chan error) go func() { mx, err := v.CheckMX(syntax.Domain) if err != nil { errCh <- err return } mxCh <- mx }() go func() { smtp, err := v.CheckSMTP(syntax.Domain, syntax.Username) if err != nil { errCh <- err return } smtpCh <- smtp }() select { case mx := <-mxCh: ret.HasMxRecords = mx.HasMXRecord case smtp := <-smtpCh: ret.SMTP = smtp ret.Reachable = v.calculateReachable(smtp) case err := <-errCh: return &ret, err case <-ctx.Done(): return &ret, ctx.Err() } if gravatarCheckEnabled { ctx, cancel = context.WithTimeout(context.Background(), 2*time.Second) defer cancel() gravatarCh := make(chan *emailVerifier.Gravatar) errCh = make(chan error) go func() { gravatar, err := v.CheckGravatar(email) if err != nil { errCh <- err return } gravatarCh <- gravatar }() select { case gravatar := <-gravatarCh: ret.Gravatar = gravatar case err := <-errCh: return &ret, err case <-ctx.Done(): return &ret, ctx.Err() } } if domainSuggestEnabled { ret.Suggestion = v.SuggestDomain(syntax.Domain) } return &ret, nil } func (v *Verifier) calculateReachable(s *emailVerifier.SMTP) string { if !smtpCheckEnabled { return reachableUnknown } if s.Deliverable { return reachableYes } if s.CatchAll { return reachableUnknown } return reachableNo } ```
git-hulk commented 3 days ago

@daison12006013 Generally looks good, thanks for your contribution. It would be great if we could add dedicated methods for those exported fields instead of turning them to a public member directly.