387 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			387 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package mailgun
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // Use these to specify a spam action when creating a new domain.
 | |
| const (
 | |
| 	// Tag the received message with headers providing a measure of its spamness.
 | |
| 	SpamActionTag = SpamAction("tag")
 | |
| 	// Prevents Mailgun from taking any action on what it perceives to be spam.
 | |
| 	SpamActionDisabled = SpamAction("disabled")
 | |
| 	// instructs Mailgun to just block or delete the message all-together.
 | |
| 	SpamActionDelete = SpamAction("delete")
 | |
| )
 | |
| 
 | |
| type SpamAction string
 | |
| 
 | |
| // A Domain structure holds information about a domain used when sending mail.
 | |
| type Domain struct {
 | |
| 	CreatedAt    RFC2822Time `json:"created_at"`
 | |
| 	SMTPLogin    string      `json:"smtp_login"`
 | |
| 	Name         string      `json:"name"`
 | |
| 	SMTPPassword string      `json:"smtp_password"`
 | |
| 	Wildcard     bool        `json:"wildcard"`
 | |
| 	SpamAction   SpamAction  `json:"spam_action"`
 | |
| 	State        string      `json:"state"`
 | |
| }
 | |
| 
 | |
| // DNSRecord structures describe intended records to properly configure your domain for use with Mailgun.
 | |
| // Note that Mailgun does not host DNS records.
 | |
| type DNSRecord struct {
 | |
| 	Priority   string
 | |
| 	RecordType string `json:"record_type"`
 | |
| 	Valid      string
 | |
| 	Name       string
 | |
| 	Value      string
 | |
| }
 | |
| 
 | |
| type DomainResponse struct {
 | |
| 	Domain              Domain      `json:"domain"`
 | |
| 	ReceivingDNSRecords []DNSRecord `json:"receiving_dns_records"`
 | |
| 	SendingDNSRecords   []DNSRecord `json:"sending_dns_records"`
 | |
| }
 | |
| 
 | |
| type domainConnectionResponse struct {
 | |
| 	Connection DomainConnection `json:"connection"`
 | |
| }
 | |
| 
 | |
| type domainsListResponse struct {
 | |
| 	// is -1 if Next() or First() have not been called
 | |
| 	TotalCount int      `json:"total_count"`
 | |
| 	Items      []Domain `json:"items"`
 | |
| }
 | |
| 
 | |
| // Specify the domain connection options
 | |
| type DomainConnection struct {
 | |
| 	RequireTLS       bool `json:"require_tls"`
 | |
| 	SkipVerification bool `json:"skip_verification"`
 | |
| }
 | |
| 
 | |
| // Specify the domain tracking options
 | |
| type DomainTracking struct {
 | |
| 	Click       TrackingStatus `json:"click"`
 | |
| 	Open        TrackingStatus `json:"open"`
 | |
| 	Unsubscribe TrackingStatus `json:"unsubscribe"`
 | |
| }
 | |
| 
 | |
| // The tracking status of a domain
 | |
| type TrackingStatus struct {
 | |
| 	Active     bool   `json:"active"`
 | |
| 	HTMLFooter string `json:"html_footer"`
 | |
| 	TextFooter string `json:"text_footer"`
 | |
| }
 | |
| 
 | |
| type domainTrackingResponse struct {
 | |
| 	Tracking DomainTracking `json:"tracking"`
 | |
| }
 | |
| 
 | |
| // ListDomains retrieves a set of domains from Mailgun.
 | |
| func (mg *MailgunImpl) ListDomains(opts *ListOptions) *DomainsIterator {
 | |
| 	var limit int
 | |
| 	if opts != nil {
 | |
| 		limit = opts.Limit
 | |
| 	}
 | |
| 
 | |
| 	if limit == 0 {
 | |
| 		limit = 100
 | |
| 	}
 | |
| 	return &DomainsIterator{
 | |
| 		mg:                  mg,
 | |
| 		url:                 generatePublicApiUrl(mg, domainsEndpoint),
 | |
| 		domainsListResponse: domainsListResponse{TotalCount: -1},
 | |
| 		limit:               limit,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type DomainsIterator struct {
 | |
| 	domainsListResponse
 | |
| 
 | |
| 	limit  int
 | |
| 	mg     Mailgun
 | |
| 	offset int
 | |
| 	url    string
 | |
| 	err    error
 | |
| }
 | |
| 
 | |
| // If an error occurred during iteration `Err()` will return non nil
 | |
| func (ri *DomainsIterator) Err() error {
 | |
| 	return ri.err
 | |
| }
 | |
| 
 | |
| // Offset returns the current offset of the iterator
 | |
| func (ri *DomainsIterator) Offset() int {
 | |
| 	return ri.offset
 | |
| }
 | |
| 
 | |
| // Next retrieves the next page of items from the api. Returns false when there
 | |
| // no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
 | |
| // the error
 | |
| func (ri *DomainsIterator) Next(ctx context.Context, items *[]Domain) bool {
 | |
| 	if ri.err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	ri.err = ri.fetch(ctx, ri.offset, ri.limit)
 | |
| 	if ri.err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	cpy := make([]Domain, len(ri.Items))
 | |
| 	copy(cpy, ri.Items)
 | |
| 	*items = cpy
 | |
| 	if len(ri.Items) == 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 	ri.offset = ri.offset + len(ri.Items)
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // First retrieves the first page of items from the api. Returns false if there
 | |
| // was an error. It also sets the iterator object to the first page.
 | |
| // Use `.Err()` to retrieve the error.
 | |
| func (ri *DomainsIterator) First(ctx context.Context, items *[]Domain) bool {
 | |
| 	if ri.err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	ri.err = ri.fetch(ctx, 0, ri.limit)
 | |
| 	if ri.err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	cpy := make([]Domain, len(ri.Items))
 | |
| 	copy(cpy, ri.Items)
 | |
| 	*items = cpy
 | |
| 	ri.offset = len(ri.Items)
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // Last retrieves the last page of items from the api.
 | |
| // Calling Last() is invalid unless you first call First() or Next()
 | |
| // Returns false if there was an error. It also sets the iterator object
 | |
| // to the last page. Use `.Err()` to retrieve the error.
 | |
| func (ri *DomainsIterator) Last(ctx context.Context, items *[]Domain) bool {
 | |
| 	if ri.err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	if ri.TotalCount == -1 {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	ri.offset = ri.TotalCount - ri.limit
 | |
| 	if ri.offset < 0 {
 | |
| 		ri.offset = 0
 | |
| 	}
 | |
| 
 | |
| 	ri.err = ri.fetch(ctx, ri.offset, ri.limit)
 | |
| 	if ri.err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	cpy := make([]Domain, len(ri.Items))
 | |
| 	copy(cpy, ri.Items)
 | |
| 	*items = cpy
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // Previous retrieves the previous page of items from the api. Returns false when there
 | |
| // no more pages to retrieve or if there was an error. Use `.Err()` to retrieve
 | |
| // the error if any
 | |
| func (ri *DomainsIterator) Previous(ctx context.Context, items *[]Domain) bool {
 | |
| 	if ri.err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	if ri.TotalCount == -1 {
 | |
| 		return false
 | |
| 	}
 | |
| 
 | |
| 	ri.offset = ri.offset - (ri.limit * 2)
 | |
| 	if ri.offset < 0 {
 | |
| 		ri.offset = 0
 | |
| 	}
 | |
| 
 | |
| 	ri.err = ri.fetch(ctx, ri.offset, ri.limit)
 | |
| 	if ri.err != nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	cpy := make([]Domain, len(ri.Items))
 | |
| 	copy(cpy, ri.Items)
 | |
| 	*items = cpy
 | |
| 	if len(ri.Items) == 0 {
 | |
| 		return false
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (ri *DomainsIterator) fetch(ctx context.Context, skip, limit int) error {
 | |
| 	r := newHTTPRequest(ri.url)
 | |
| 	r.setBasicAuth(basicAuthUser, ri.mg.APIKey())
 | |
| 	r.setClient(ri.mg.Client())
 | |
| 
 | |
| 	if skip != 0 {
 | |
| 		r.addParameter("skip", strconv.Itoa(skip))
 | |
| 	}
 | |
| 	if limit != 0 {
 | |
| 		r.addParameter("limit", strconv.Itoa(limit))
 | |
| 	}
 | |
| 
 | |
| 	return getResponseFromJSON(ctx, r, &ri.domainsListResponse)
 | |
| }
 | |
| 
 | |
| // GetDomain retrieves detailed information about the named domain.
 | |
| func (mg *MailgunImpl) GetDomain(ctx context.Context, domain string) (DomainResponse, error) {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain)
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 	var resp DomainResponse
 | |
| 	err := getResponseFromJSON(ctx, r, &resp)
 | |
| 	return resp, err
 | |
| }
 | |
| 
 | |
| func (mg *MailgunImpl) VerifyDomain(ctx context.Context, domain string) (string, error) {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/verify")
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 
 | |
| 	payload := newUrlEncodedPayload()
 | |
| 	var resp DomainResponse
 | |
| 	err := putResponseFromJSON(ctx, r, payload, &resp)
 | |
| 	return resp.Domain.State, err
 | |
| }
 | |
| 
 | |
| // Optional parameters when creating a domain
 | |
| type CreateDomainOptions struct {
 | |
| 	Password           string
 | |
| 	SpamAction         SpamAction
 | |
| 	Wildcard           bool
 | |
| 	ForceDKIMAuthority bool
 | |
| 	DKIMKeySize        int
 | |
| 	IPS                []string
 | |
| }
 | |
| 
 | |
| // CreateDomain instructs Mailgun to create a new domain for your account.
 | |
| // The name parameter identifies the domain.
 | |
| // The smtpPassword parameter provides an access credential for the domain.
 | |
| // The spamAction domain must be one of Delete, Tag, or Disabled.
 | |
| // The wildcard parameter instructs Mailgun to treat all subdomains of this domain uniformly if true,
 | |
| // and as different domains if false.
 | |
| func (mg *MailgunImpl) CreateDomain(ctx context.Context, name string, opts *CreateDomainOptions) (DomainResponse, error) {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint))
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 
 | |
| 	payload := newUrlEncodedPayload()
 | |
| 	payload.addValue("name", name)
 | |
| 
 | |
| 	if opts != nil {
 | |
| 		if opts.SpamAction != "" {
 | |
| 			payload.addValue("spam_action", string(opts.SpamAction))
 | |
| 		}
 | |
| 		if opts.Wildcard {
 | |
| 			payload.addValue("wildcard", boolToString(opts.Wildcard))
 | |
| 		}
 | |
| 		if opts.ForceDKIMAuthority {
 | |
| 			payload.addValue("force_dkim_authority", boolToString(opts.ForceDKIMAuthority))
 | |
| 		}
 | |
| 		if opts.DKIMKeySize != 0 {
 | |
| 			payload.addValue("dkim_key_size", strconv.Itoa(opts.DKIMKeySize))
 | |
| 		}
 | |
| 		if len(opts.IPS) != 0 {
 | |
| 			payload.addValue("ips", strings.Join(opts.IPS, ","))
 | |
| 		}
 | |
| 		if len(opts.Password) != 0 {
 | |
| 			payload.addValue("smtp_password", opts.Password)
 | |
| 		}
 | |
| 	}
 | |
| 	var resp DomainResponse
 | |
| 	err := postResponseFromJSON(ctx, r, payload, &resp)
 | |
| 	return resp, err
 | |
| }
 | |
| 
 | |
| // GetDomainConnection returns delivery connection settings for the defined domain
 | |
| func (mg *MailgunImpl) GetDomainConnection(ctx context.Context, domain string) (DomainConnection, error) {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/connection")
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 	var resp domainConnectionResponse
 | |
| 	err := getResponseFromJSON(ctx, r, &resp)
 | |
| 	return resp.Connection, err
 | |
| }
 | |
| 
 | |
| // Updates the specified delivery connection settings for the defined domain
 | |
| func (mg *MailgunImpl) UpdateDomainConnection(ctx context.Context, domain string, settings DomainConnection) error {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/connection")
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 
 | |
| 	payload := newUrlEncodedPayload()
 | |
| 	payload.addValue("require_tls", boolToString(settings.RequireTLS))
 | |
| 	payload.addValue("skip_verification", boolToString(settings.SkipVerification))
 | |
| 	_, err := makePutRequest(ctx, r, payload)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // DeleteDomain instructs Mailgun to dispose of the named domain name
 | |
| func (mg *MailgunImpl) DeleteDomain(ctx context.Context, name string) error {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + name)
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 	_, err := makeDeleteRequest(ctx, r)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // GetDomainTracking returns tracking settings for a domain
 | |
| func (mg *MailgunImpl) GetDomainTracking(ctx context.Context, domain string) (DomainTracking, error) {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking")
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 	var resp domainTrackingResponse
 | |
| 	err := getResponseFromJSON(ctx, r, &resp)
 | |
| 	return resp.Tracking, err
 | |
| }
 | |
| 
 | |
| func (mg *MailgunImpl) UpdateClickTracking(ctx context.Context, domain, active string) error {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/click")
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 
 | |
| 	payload := newUrlEncodedPayload()
 | |
| 	payload.addValue("active", active)
 | |
| 	_, err := makePutRequest(ctx, r, payload)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func (mg *MailgunImpl) UpdateUnsubscribeTracking(ctx context.Context, domain, active, htmlFooter, textFooter string) error {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/unsubscribe")
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 
 | |
| 	payload := newUrlEncodedPayload()
 | |
| 	payload.addValue("active", active)
 | |
| 	payload.addValue("html_footer", htmlFooter)
 | |
| 	payload.addValue("text_footer", textFooter)
 | |
| 	_, err := makePutRequest(ctx, r, payload)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func (mg *MailgunImpl) UpdateOpenTracking(ctx context.Context, domain, active string) error {
 | |
| 	r := newHTTPRequest(generatePublicApiUrl(mg, domainsEndpoint) + "/" + domain + "/tracking/open")
 | |
| 	r.setClient(mg.Client())
 | |
| 	r.setBasicAuth(basicAuthUser, mg.APIKey())
 | |
| 
 | |
| 	payload := newUrlEncodedPayload()
 | |
| 	payload.addValue("active", active)
 | |
| 	_, err := makePutRequest(ctx, r, payload)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| func boolToString(b bool) string {
 | |
| 	if b {
 | |
| 		return "true"
 | |
| 	}
 | |
| 	return "false"
 | |
| }
 |