github.com/go-email-validator/go-email-validator@v0.0.0-20230409163946-b8b9e6a0552e/pkg/ev/evsmtp/proxy.go (about) 1 package evsmtp 2 3 import ( 4 "context" 5 "github.com/go-email-validator/go-email-validator/pkg/ev/evsmtp/smtpclient" 6 "github.com/tevino/abool" 7 "h12.io/socks" 8 "net" 9 "net/smtp" 10 ) 11 12 // TCPConnection is tcp name 13 const TCPConnection = "tcp" 14 15 // DialFunc is function type to create smtpclient.SMTPClient 16 type DialFunc func(ctx context.Context, addr, proxyURL string) (smtpclient.SMTPClient, error) 17 18 var smtpNewClient = smtp.NewClient 19 20 var directDial = DirectDial 21 22 // DirectDial generates smtpclient.SMTPClient (smtp.Client) 23 func DirectDial(ctx context.Context, addr, proxyURL string) (smtpclient.SMTPClient, error) { 24 d := net.Dialer{} 25 conn, err := d.DialContext(ctx, TCPConnection, addr) 26 if err != nil { 27 return nil, err 28 } 29 host, _, _ := net.SplitHostPort(addr) 30 return smtpNewClient(conn, host) 31 } 32 33 var h12ioDial = socks.Dial 34 35 // H12IODial generates smtpclient.SMTPClient (smtp.Client) with proxy in socks.Dial 36 func H12IODial(ctx context.Context, addr, proxyURL string) (smtpclient.SMTPClient, error) { 37 if proxyURL == "" { 38 return directDial(ctx, addr, proxyURL) 39 } 40 var c net.Conn 41 var client smtpclient.SMTPClient = nil 42 var err error 43 p := h12ioDial(proxyURL) 44 45 done := make(chan struct{}, 1) 46 needClose := abool.New() 47 go func() { 48 c, err = p("tcp", addr) 49 defer func() { 50 defer func() { close(done) }() 51 52 if needClose.IsSet() && c != nil { 53 c.Close() 54 } 55 }() 56 57 if err != nil { 58 return 59 } 60 61 host, _, _ := net.SplitHostPort(addr) 62 client, err = smtpNewClient(c, host) 63 }() 64 65 select { 66 case <-ctx.Done(): 67 needClose.Set() 68 return nil, ctx.Err() 69 case <-done: 70 return client, err 71 } 72 }