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  }