diff --git a/email_validation.go b/email_validation.go deleted file mode 100644 index 3589f81..0000000 --- a/email_validation.go +++ /dev/null @@ -1,137 +0,0 @@ -package mailgun - -import ( - "context" - "fmt" - "net/http" - "os" - - "github.com/mailgun/errors" -) - -// EmailVerification records basic facts about a validated e-mail address. -// See the ValidateEmail method and example for more details. -type EmailVerification struct { - // Echoes the address provided. - Address string `json:"address"` - - // Indicates whether Mailgun thinks the address is from a known - // disposable mailbox provider. - IsDisposableAddress bool `json:"is_disposable_address"` - - // Indicates whether Mailgun thinks the address is an email distribution list. - IsRoleAddress bool `json:"is_role_address"` - - // A list of potential reasons why a specific validation may be unsuccessful. (Available in the v4 response) - Reason []string `json:"reason"` - - // Result - Result string `json:"result"` - - // Risk assessment for the provided email. - Risk string `json:"risk"` - - LastSeen int64 `json:"last_seen,omitempty"` - - // Provides a simple recommendation in case the address is invalid or - // Mailgun thinks you might have a typo. May be empty, in which case - // Mailgun has no recommendation to give. - DidYouMean string `json:"did_you_mean,omitempty"` - - // Engagement results are a macro-level view that explain an email recipient’s propensity to engage. - // https://documentation.mailgun.com/docs/inboxready/mailgun-validate/validate_engagement/ - Engagement *EngagementData `json:"engagement,omitempty"` - - RootAddress string `json:"root_address,omitempty"` -} - -type EngagementData struct { - Engaging bool `json:"engaging"` - IsBot bool `json:"is_bot"` - Behavior string `json:"behavior,omitempty"` -} - -type EmailValidator interface { - ValidateEmail(ctx context.Context, email string, mailBoxVerify bool) (EmailVerification, error) -} - -// TODO(v5): switch to MailgunImpl -type EmailValidatorImpl struct { - client *http.Client - apiBase string - apiKey string -} - -// NewEmailValidator creates a new validation instance. -// Use private key. -func NewEmailValidator(apiKey string) *EmailValidatorImpl { - return &EmailValidatorImpl{ - // TODO(vtopc): Don’t use http.DefaultClient - https://medium.com/@nate510/don-t-use-go-s-default-http-client-4804cb19f779 - client: http.DefaultClient, - apiBase: "https://api.mailgun.net/v4", - apiKey: apiKey, - } -} - -// NewEmailValidatorFromEnv returns a new EmailValidator using environment variables -// -// Set MG_API_KEY -func NewEmailValidatorFromEnv() (*EmailValidatorImpl, error) { - apiKey := os.Getenv("MG_API_KEY") - if apiKey == "" { - return nil, errors.New( - "environment variable MG_API_KEY required for email validation") - } - - v := NewEmailValidator(apiKey) - url := os.Getenv("MG_URL") - if url != "" { - v.SetAPIBase(url) - } - return v, nil -} - -// APIBase returns the API Base URL configured for this client. -func (m *EmailValidatorImpl) APIBase() string { - return m.apiBase -} - -// SetAPIBase updates the API Base URL for this client. -func (m *EmailValidatorImpl) SetAPIBase(address string) { - m.apiBase = address -} - -// SetClient updates the HTTP client for this client. -func (m *EmailValidatorImpl) SetClient(c *http.Client) { - m.client = c -} - -// Client returns the HTTP client configured for this client. -func (m *EmailValidatorImpl) Client() *http.Client { - return m.client -} - -// APIKey returns the API key used for validations -func (m *EmailValidatorImpl) APIKey() string { - return m.apiKey -} - -// ValidateEmail performs various checks on the email address provided to ensure it's correctly formatted. -// It may also be used to break an email address into its sub-components. If user has set the -// TODO(v5): move to *MailgunImpl? -func (m *EmailValidatorImpl) ValidateEmail(ctx context.Context, email string, mailBoxVerify bool) (EmailVerification, error) { - r := newHTTPRequest(fmt.Sprintf("%s/v4/address/validate", m.APIBase())) - r.setClient(m.Client()) - r.addParameter("address", email) - if mailBoxVerify { - r.addParameter("mailbox_verification", "true") - } - r.setBasicAuth(basicAuthUser, m.APIKey()) - - var res EmailVerification - err := getResponseFromJSON(ctx, r, &res) - if err != nil { - return EmailVerification{}, err - } - return res, nil -} diff --git a/examples/examples.go b/examples/examples.go index da2b4b5..f04ab4c 100644 --- a/examples/examples.go +++ b/examples/examples.go @@ -608,13 +608,13 @@ func ListUnsubscribes(domain, apiKey string) ([]mailgun.Unsubscribe, error) { return result, nil } -func ValidateEmail(apiKey string) (mailgun.EmailVerification, error) { - mv := mailgun.NewEmailValidator(apiKey) +func ValidateEmail(apiKey string) (mailgun.ValidateEmailResponse, error) { + mg := mailgun.NewMailgun(apiKey) ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) defer cancel() - return mv.ValidateEmail(ctx, "foo@mailgun.net", false) + return mg.ValidateEmail(ctx, "foo@mailgun.net", false) } func GetWebhook(domain, apiKey string) ([]string, error) { diff --git a/examples_test.go b/examples_test.go index 261a214..1e296ab 100644 --- a/examples_test.go +++ b/examples_test.go @@ -15,13 +15,13 @@ import ( "github.com/mailgun/mailgun-go/v4/events" ) -func ExampleEmailValidatorImpl_ValidateEmail() { - v := mailgun.NewEmailValidator("my_api_key") +func ExampleMailgunImpl_ValidateEmail() { + mg := mailgun.NewMailgun("my_api_key") ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() - ev, err := v.ValidateEmail(ctx, "joe@example.com", false) + ev, err := mg.ValidateEmail(ctx, "joe@example.com", false) if err != nil { log.Fatal(err) } diff --git a/mailgun.go b/mailgun.go index 03d78c5..c62a438 100644 --- a/mailgun.go +++ b/mailgun.go @@ -234,6 +234,8 @@ type Mailgun interface { DeleteTemplateVersion(ctx context.Context, domain, templateName, tag string) error ListTemplateVersions(domain, templateName string, opts *ListOptions) *TemplateVersionsIterator + ValidateEmail(ctx context.Context, email string, mailBoxVerify bool) (ValidateEmailResponse, error) + ListSubaccounts(opts *ListSubaccountsOptions) *SubaccountsIterator CreateSubaccount(ctx context.Context, subaccountName string) (SubaccountResponse, error) SubaccountDetails(ctx context.Context, subaccountId string) (SubaccountResponse, error) diff --git a/mock_validation.go b/mock_validation.go index 29291a5..8d4a918 100644 --- a/mock_validation.go +++ b/mock_validation.go @@ -17,7 +17,7 @@ func (ms *mockServer) validateEmailV4(w http.ResponseWriter, r *http.Request) { return } - var results EmailVerification + var results ValidateEmailResponse results.Address = r.FormValue("address") results.Reason = []string{"no-reason"} results.Risk = "unknown" diff --git a/validation.go b/validation.go new file mode 100644 index 0000000..1fedc36 --- /dev/null +++ b/validation.go @@ -0,0 +1,69 @@ +package mailgun + +import ( + "context" + "fmt" +) + +// ValidateEmailResponse records basic facts about a validated e-mail address. +// See the ValidateEmail method and example for more details. +type ValidateEmailResponse struct { + // Echoes the address provided. + Address string `json:"address"` + + // Indicates whether Mailgun thinks the address is from a known + // disposable mailbox provider. + IsDisposableAddress bool `json:"is_disposable_address"` + + // Indicates whether Mailgun thinks the address is an email distribution list. + IsRoleAddress bool `json:"is_role_address"` + + // A list of potential reasons why a specific validation may be unsuccessful. (Available in the v4 response) + Reason []string `json:"reason"` + + // Result + Result string `json:"result"` + + // Risk assessment for the provided email. + Risk string `json:"risk"` + + LastSeen int64 `json:"last_seen,omitempty"` + + // Provides a simple recommendation in case the address is invalid or + // Mailgun thinks you might have a typo. May be empty, in which case + // Mailgun has no recommendation to give. + DidYouMean string `json:"did_you_mean,omitempty"` + + // Engagement results are a macro-level view that explain an email recipient’s propensity to engage. + // https://documentation.mailgun.com/docs/inboxready/mailgun-validate/validate_engagement/ + Engagement *EngagementData `json:"engagement,omitempty"` + + RootAddress string `json:"root_address,omitempty"` +} + +type EngagementData struct { + Engaging bool `json:"engaging"` + IsBot bool `json:"is_bot"` + Behavior string `json:"behavior,omitempty"` +} + +// ValidateEmail performs various checks on the email address provided to ensure it's correctly formatted. +// It may also be used to break an email address into its sub-components. +// https://documentation.mailgun.com/docs/inboxready/mailgun-validate/single-valid-ir/ +func (mg *MailgunImpl) ValidateEmail(ctx context.Context, email string, mailBoxVerify bool) (ValidateEmailResponse, error) { + r := newHTTPRequest(fmt.Sprintf("%s/v4/address/validate", mg.APIBase())) + r.setClient(mg.HTTPClient()) + r.addParameter("address", email) + if mailBoxVerify { + r.addParameter("mailbox_verification", "true") + } + r.setBasicAuth(basicAuthUser, mg.APIKey()) + + var res ValidateEmailResponse + err := getResponseFromJSON(ctx, r, &res) + if err != nil { + return ValidateEmailResponse{}, err + } + + return res, nil +} diff --git a/email_validation_test.go b/validation_test.go similarity index 75% rename from email_validation_test.go rename to validation_test.go index 2d9edca..2409cb3 100644 --- a/email_validation_test.go +++ b/validation_test.go @@ -9,13 +9,14 @@ import ( "github.com/stretchr/testify/require" ) -func TestEmailValidationV4(t *testing.T) { - v := mailgun.NewEmailValidator(testKey) - v.SetAPIBase(server.URL()) +func TestValidateEmail(t *testing.T) { + mg := mailgun.NewMailgun(testKey) + err := mg.SetAPIBase(server.URL()) + require.NoError(t, err) ctx := context.Background() - ev, err := v.ValidateEmail(ctx, "foo@mailgun.com", false) + ev, err := mg.ValidateEmail(ctx, "foo@mailgun.com", false) require.NoError(t, err) assert.False(t, ev.IsDisposableAddress)