github.com/mailgun/mailgun-go/v3@v3.6.4/email_validation.go (about) 1 package mailgun 2 3 import ( 4 "context" 5 "fmt" 6 "net/http" 7 "os" 8 "strings" 9 10 "github.com/pkg/errors" 11 ) 12 13 // The EmailVerificationParts structure breaks out the basic elements of an email address. 14 // LocalPart includes everything up to the '@' in an e-mail address. 15 // Domain includes everything after the '@'. 16 // DisplayName is no longer used, and will appear as "". 17 type EmailVerificationParts struct { 18 LocalPart string `json:"local_part"` 19 Domain string `json:"domain"` 20 DisplayName string `json:"display_name"` 21 } 22 23 // EmailVerification records basic facts about a validated e-mail address. 24 // See the ValidateEmail method and example for more details. 25 // 26 type EmailVerification struct { 27 // Indicates whether an email address conforms to IETF RFC standards. 28 IsValid bool `json:"is_valid"` 29 // Indicates whether an email address is deliverable. 30 MailboxVerification string `json:"mailbox_verification"` 31 // Parts records the different subfields of the parsed email address 32 Parts EmailVerificationParts `json:"parts"` 33 // Echoes the address provided. 34 Address string `json:"address"` 35 // Provides a simple recommendation in case the address is invalid or 36 // Mailgun thinks you might have a typo. May be empty, in which case 37 // Mailgun has no recommendation to give. 38 DidYouMean string `json:"did_you_mean"` 39 // Indicates whether Mailgun thinks the address is from a known 40 // disposable mailbox provider. 41 IsDisposableAddress bool `json:"is_disposable_address"` 42 // Indicates whether Mailgun thinks the address is an email distribution list. 43 IsRoleAddress bool `json:"is_role_address"` 44 // A human readable reason the address is reported as invalid 45 Reason string `json:"reason"` 46 } 47 48 type addressParseResult struct { 49 Parsed []string `json:"parsed"` 50 Unparseable []string `json:"unparseable"` 51 } 52 53 type EmailValidator interface { 54 ValidateEmail(ctx context.Context, email string, mailBoxVerify bool) (EmailVerification, error) 55 ParseAddresses(ctx context.Context, addresses ...string) ([]string, []string, error) 56 } 57 58 type EmailValidatorImpl struct { 59 client *http.Client 60 isPublicKey bool 61 apiBase string 62 apiKey string 63 } 64 65 // Creates a new validation instance. 66 // * If a public key is provided, uses the public validation endpoints 67 // * If a private key is provided, uses the private validation endpoints 68 func NewEmailValidator(apiKey string) *EmailValidatorImpl { 69 isPublicKey := false 70 71 // Did the user pass in a public key? 72 if strings.HasPrefix(apiKey, "pubkey-") { 73 isPublicKey = true 74 } 75 76 return &EmailValidatorImpl{ 77 client: http.DefaultClient, 78 isPublicKey: isPublicKey, 79 apiBase: APIBase, 80 apiKey: apiKey, 81 } 82 } 83 84 // NewEmailValidatorFromEnv returns a new EmailValidator using environment variables 85 // If MG_PUBLIC_API_KEY is set, assume using the free validation subject to daily usage limits 86 // If only MG_API_KEY is set, assume using the /private validation routes with no daily usage limits 87 func NewEmailValidatorFromEnv() (*EmailValidatorImpl, error) { 88 apiKey := os.Getenv("MG_PUBLIC_API_KEY") 89 if apiKey == "" { 90 apiKey = os.Getenv("MG_API_KEY") 91 if apiKey == "" { 92 return nil, errors.New( 93 "environment variable MG_PUBLIC_API_KEY or MG_API_KEY required for email validation") 94 } 95 } 96 v := NewEmailValidator(apiKey) 97 url := os.Getenv("MG_URL") 98 if url != "" { 99 v.SetAPIBase(url) 100 } 101 return v, nil 102 } 103 104 // APIBase returns the API Base URL configured for this client. 105 func (m *EmailValidatorImpl) APIBase() string { 106 return m.apiBase 107 } 108 109 // SetAPIBase updates the API Base URL for this client. 110 func (m *EmailValidatorImpl) SetAPIBase(address string) { 111 m.apiBase = address 112 } 113 114 // SetClient updates the HTTP client for this client. 115 func (m *EmailValidatorImpl) SetClient(c *http.Client) { 116 m.client = c 117 } 118 119 // Client returns the HTTP client configured for this client. 120 func (m *EmailValidatorImpl) Client() *http.Client { 121 return m.client 122 } 123 124 // APIKey returns the API key used for validations 125 func (m *EmailValidatorImpl) APIKey() string { 126 return m.apiKey 127 } 128 129 func (m *EmailValidatorImpl) getAddressURL(endpoint string) string { 130 if m.isPublicKey { 131 return fmt.Sprintf("%s/address/%s", m.APIBase(), endpoint) 132 } 133 return fmt.Sprintf("%s/address/private/%s", m.APIBase(), endpoint) 134 } 135 136 // ValidateEmail performs various checks on the email address provided to ensure it's correctly formatted. 137 // It may also be used to break an email address into its sub-components. (See example.) 138 func (m *EmailValidatorImpl) ValidateEmail(ctx context.Context, email string, mailBoxVerify bool) (EmailVerification, error) { 139 r := newHTTPRequest(m.getAddressURL("validate")) 140 r.setClient(m.Client()) 141 r.addParameter("address", email) 142 if mailBoxVerify { 143 r.addParameter("mailbox_verification", "true") 144 } 145 r.setBasicAuth(basicAuthUser, m.APIKey()) 146 147 var response EmailVerification 148 err := getResponseFromJSON(ctx, r, &response) 149 if err != nil { 150 return EmailVerification{}, err 151 } 152 153 return response, nil 154 } 155 156 // ParseAddresses takes a list of addresses and sorts them into valid and invalid address categories. 157 // NOTE: Use of this function requires a proper public API key. The private API key will not work. 158 func (m *EmailValidatorImpl) ParseAddresses(ctx context.Context, addresses ...string) ([]string, []string, error) { 159 r := newHTTPRequest(m.getAddressURL("parse")) 160 r.setClient(m.Client()) 161 r.addParameter("addresses", strings.Join(addresses, ",")) 162 r.setBasicAuth(basicAuthUser, m.APIKey()) 163 164 var response addressParseResult 165 err := getResponseFromJSON(ctx, r, &response) 166 if err != nil { 167 return nil, nil, err 168 } 169 170 return response.Parsed, response.Unparseable, nil 171 }