improvmx

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 20, 2021 License: MIT Imports: 4 Imported by: 0

README

Overview

Go Reference Build and Tests Code Coverage

go-improvmx is a golang wrapper around the ImprovMX API. It was written primarily for a terraform provider, however others might get use out of it.

Installation

Inside your go.mod, add

require occult.work/improvmx

Development

go-improvmx uses task to run the most common operations. These tasks are then duplicated with extra flags within the GitHub Actions workflow.

Task has instructions on installation. Once installed, simply run task from the project directory.

Dependencies

The current list of third party libraries are

The following libraries are used for testing only

Documentation

Overview

ImprovMX is a software as a service that allows setting up email forwarding in seconds and comes with free, premium, and business tiers. This package is able to wrap the entire API documented https://improvmx.com/api however not all features will work across all tiers. At the present time, only the v3 API is supported.

Within this documentation, the REST API is refered to the as the ImprovMX REST API, and the golang API is simply called either the golang API or just "the API".

Usage

The improvmx package is designed to be used with go modules enabled only.

import "occult.work/improvmx"

Examples

Construct a new API session, then access different parts of the ImprovMX REST API. For example:

session, error := improvmx.New("authentication-token")
// List all aliases for domain "example.com"
aliases, error := session.Aliases.List(context.Background(), "example.com")
for alias := range aliases {
	fmt.Printf("%s: %s\n", alias.Name, alias.Address)
}

Endpoints

The ImprovMX REST API has several endpoints to access information regarding Domains, Aliases, SMTP Credentials, and Logs for both Domains and Aliases. Unlike the ImprovMX REST API, however, the golang API has organized these endpoints into Domain, Aliases, Account, and Credentials. Every operation within these endpoints attempts to follow the CRUD (Create, Read, Update, Delete) naming convention. There are some outliers, such as Account.Labels, or Domain.Verify. Additionally, logs are grouped with their specific endpoints. Users are also able to List some resources:

domains, error := session.Domains.List()

Due to limitations with the ImprovMX REST API, the Credentials endpoint does not permit reading a single entry.

Authentication

The ImprovMX REST API currently uses a simple authentication scheme. The package will take care of setting this authentication scheme for users. Simply construct a Session with the desired token, and the API will (assuming a valid API Token) "just work"

Pagination

Several ImprovMX REST API endpoints currently use pagination to receive results. At this time, the golang API does not support preventing pagination, nor does it support manual pagination.

This will be fixed in the future.

Example (Account)
package main

import (
	"context"
	"fmt"
	"log"

	"occult.work/improvmx"
)

func main() {
	session, error := improvmx.New("token")
	if error != nil {
		log.Fatal(error)
	}
	account, error := session.Account.Read(context.Background())
	if error != nil {
		log.Fatal(error)
	}
	fmt.Printf("Name: %s\tPlan: %s\n", account.CompanyName, account.Plan.Name)
}
Output:

Example (Aliases)
package main

import (
	"context"
	"fmt"
	"log"

	"occult.work/improvmx"
)

func main() {
	session, error := improvmx.New("token")
	if error != nil {
		log.Fatal(error)
	}
	options := improvmx.NewListOption().
		SetIsActive(true).
		SetStartsWith("r")
	aliases, error := session.Aliases.List(context.Background(), "example.com", options)
	if error != nil {
		log.Fatal(error)
	}
	for _, alias := range aliases {
		fmt.Printf("%s <%s>\n", alias.Name, alias.Address)
	}
}
Output:

Example (Credentials)
package main

import (
	"context"
	"fmt"
	"log"

	"occult.work/improvmx"
)

func main() {
	session, error := improvmx.New("token")
	if error != nil {
		log.Fatal(error)
	}
	ctx := context.Background()
	account, error := session.Account.Read(ctx)
	if error != nil {
		log.Fatal(error)
	}
	if !account.Premium {
		log.Fatal("SMTP Credentials are a premium account feature")
	}
	credentials, error := session.Credentials.List(ctx, "example.com")
	if error != nil {
		log.Fatal(error)
	}
	for _, credential := range credentials {
		fmt.Println(credential.Username)
	}
}
Output:

Example (Domains)
package main

import ()

func main() {

}
Output:

Example (Logs)
package main

import (
	"context"
	"fmt"
	"log"

	"occult.work/improvmx"
)

func main() {
	session, error := improvmx.New("token")
	if error != nil {
		log.Fatal(error)
	}
	logs, error := session.Aliases.Logs(context.Background(), "example.com", "richard")
	if error != nil {
		log.Fatal(error)
	}

	for _, entry := range logs {
		fmt.Printf("ID: %s, Hostname: %s, Subject: %s",
			entry.ID,
			entry.Hostname,
			entry.Subject)
	}
}
Output:

Index

Examples

Constants

View Source
const (
	// The email was accepted to be processed
	Queued MessageStatus = "QUEUED"

	// The email was refused at the SMTP connection
	Refused = "REFUSED"

	// The email was successfully delivered to the end destination
	Delievered = "DELIVERED"

	// The end destination refused the email temporarily. ImprovMX will try again
	// multiple times with increased delay between
	SoftBounce = "SOFT-BOUNCE"

	// The end destination couldn't accept the email definitively
	HardBounce = "HARD-BOUNCE"
)
View Source
const (
	//BaseURLv3 is the base URL for the improvmx API
	BaseURLv3 = "https://api.improvmx.com/v3"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type Account

type Account struct {
	BillingEmail   string `json:"billing_email"`
	CancelsOn      Time   `json:"cancels_on"`
	CardBrand      string `json:"card_brand"`
	CompanyDetails string `json:"company_details"`
	CompanyName    string `json:"company_name"`
	CompanyVAT     string `json:"company_vat"`
	Country        string `json:"country"`
	CreatedAt      Time   `json:"created"`
	Email          string `json:"email"`
	Last4          string `json:"last4"`
	Limits         struct {
		Aliases      int `json:"aliases"`
		DailyQuota   int `json:"daily_quota"`
		Domains      int `json:"domains"`
		RateLimit    int `json:"ratelimit"`
		Redirections int `json:"redirections"`
		Subdomains   int `json:"subdomains"`
	} `json:"limits"`
	LockReason   string       `json:"lock_reason"`
	Locked       bool         `json:"locked"`
	Password     bool         `json:"password"`
	Plan         *AccountPlan `json:"plan"`
	Premium      bool         `json:"premium"`
	PrivacyLevel int64        `json:"privacy_level"`
	RenewDate    Time         `json:"renew_date"`
}

type AccountEndpoint

type AccountEndpoint doze.Client

func (*AccountEndpoint) Labels

func (endpoint *AccountEndpoint) Labels(ctx context.Context) ([]Whitelabel, error)

Returns the domains used as whitelabels associated with the account.

func (*AccountEndpoint) Read

func (endpoint *AccountEndpoint) Read(ctx context.Context) (*Account, error)

Returns an instance of the Account

type AccountPlan

type AccountPlan struct {
	AliasesLimit int64  `json:"aliases_limit"`
	DailyQuota   int64  `json:"daily_quota"`
	DomainsLimit int64  `json:"domains_limit"`
	Kind         string `json:"kind"`
	Name         string `json:"name"`
	Price        int64  `json:"price"`
	Yearly       bool   `json:"yearly"`
}

type Alias

type Alias struct {
	// The address the Alias will forward to
	Address string `json:"forward"`
	Name    string `json:"alias"`
	ID      int64  `json:"id"`
}

type AliasEndpoint

type AliasEndpoint doze.Client

Used to interact with the email alias specific parts of the ImprovMX REST API

func (*AliasEndpoint) Create

func (endpoint *AliasEndpoint) Create(ctx context.Context, domain, alias, address string) (*Alias, error)

Creates a new alias for the given domain

See the API reference for more information: https://improvmx.com/api/#alias-add

func (*AliasEndpoint) Delete

func (endpoint *AliasEndpoint) Delete(ctx context.Context, domain, alias string) error

Deletes a single for the given domain and alias

See the API reference for more information: https://improvmx.com/api/#alias-delete

func (*AliasEndpoint) List

func (endpoint *AliasEndpoint) List(ctx context.Context, domain string, options ...*ListOption) ([]Alias, error)

Returns a slice of Alias for the given domain.

If multiple *ListOption are passed, only the first one is used.

See the API reference for more information: https://improvmx.com/api/#alias-list

func (*AliasEndpoint) Logs

func (endpoint *AliasEndpoint) Logs(ctx context.Context, domain, alias string) ([]LogEntry, error)

Retrieve the logs for the given alias in the given domain.

See the API reference for more information: https://improvmx.com/api/#logs-alias

func (*AliasEndpoint) Read

func (endpoint *AliasEndpoint) Read(ctx context.Context, domain, alias string) (*Alias, error)

Returns a single alias object for the named domain and alias

See the API reference for more information: https://improvmx.com/api/#alias-details

func (*AliasEndpoint) Update

func (endpoint *AliasEndpoint) Update(ctx context.Context, domain, alias, address string) (*Alias, error)

Updates a single alias for the given domain and alias

See the API reference for more information: https://improvmx.com/api/#alias-update

type Contact

type Contact struct {
	Email string `json:"email"`
	Name  string `json:"name"`
}

type Credential

type Credential struct {
	CreatedAt Time   `json:"created"`
	Username  string `json:"username"`
	Usage     int64  `json:"usage"`
}

type CredentialEndpoint

type CredentialEndpoint doze.Client

func (*CredentialEndpoint) Create

func (endpoint *CredentialEndpoint) Create(ctx context.Context, domain string, user User) (*Credential, error)

Adds a new SMTP account to send emails

See the API reference for more information: https://improvmx.com/api/#smtp-add

func (*CredentialEndpoint) Delete

func (endpoint *CredentialEndpoint) Delete(ctx context.Context, domain, username string) error

Deletes the given SMTP user for the given domain

See the API reference for more information: https://improvmx.com/api/#smtp-delete

func (*CredentialEndpoint) List

func (endpoint *CredentialEndpoint) List(ctx context.Context, domain string) ([]Credential, error)

Returns a list of SMTP credentials for the given domain.

Accessing the SMTP Credentials API is a premium feature tied to the ImprovMX account

See the API reference for more information: https://improvmx.com/api/#smtp-list

func (*CredentialEndpoint) Update

func (endpoint *CredentialEndpoint) Update(ctx context.Context, domain string, user User) (*Credential, error)

Updates the password for the given user

See the API reference for more information: https://improvmx.com/api/#smtp-update

type Domain

type Domain struct {
	Active            bool    `json:"active"`
	Name              string  `json:"domain"`
	Display           string  `json:"display"`
	DKIMSelector      string  `json:"dkim_selector"`
	NotificationEmail string  `json:"notification_email"`
	Whitelabel        string  `json:"white_label"`
	Added             Time    `json:"added"`
	Aliases           []Alias `json:"aliases"`
}

type DomainEndpoint

type DomainEndpoint doze.Client

func (*DomainEndpoint) Create

func (endpoint *DomainEndpoint) Create(ctx context.Context, domain string, options ...DomainOption) (*Domain, error)

Adds a new domain to the given account, with an optional email and whitelabel. If more than one DomainOption is passed to the function, it will be ignored.

See the API reference for more information: https://improvmx.com/api/#domains-add

func (*DomainEndpoint) Delete

func (endpoint *DomainEndpoint) Delete(ctx context.Context, domain string) error

Deletes the given domain from the account

See the API reference for more information: https://improvmx.com/api/#domain-delete

func (*DomainEndpoint) List

func (endpoint *DomainEndpoint) List(ctx context.Context, options ...*ListOption) ([]Domain, error)

Returns a slice of domain information for the session

If multiple *ListOption are passed, only the first one is used.

See the API reference for more information: https://improvmx.com/api/#domains-list

func (*DomainEndpoint) Logs

func (endpoint *DomainEndpoint) Logs(ctx context.Context, domain string) ([]LogEntry, error)

Retrieve the logs for the given domain.

See the API reference for more information: https://improvmx.com/api/#logs-list

func (*DomainEndpoint) Read

func (endpoint *DomainEndpoint) Read(ctx context.Context, domain string) (*Domain, error)

func (*DomainEndpoint) Update

func (endpoint *DomainEndpoint) Update(ctx context.Context, domain string, options ...DomainOption) (*Domain, error)

Updates the notification email or whitelabel for the given domain. If more than one DomainOption is passed to the function, it will be ignored

It is not possible to change the domain name.

See the API reference for more information: https://improvmx.com/api/#domain-update

func (*DomainEndpoint) Verify

func (endpoint *DomainEndpoint) Verify(ctx context.Context, domain string) error

Check if the MX entries are valid for a given domain. No error is returned if the entries are valid.

NOTE: This currently only returns an error if the domain information is not valid, however this is because we are swallowing the actual JSON output returned by the ImprovMX REST API. At some point in the future, Verify will be a wrapper around another function that returns the actual deserialized data.

type DomainOption

type DomainOption struct {
	Email string `json:"notification_email,omitempty"`
	Label string `json:"whitelabel,omitempty"`
}

Used for creating or updating a domain entry

type DomainRecord

type DomainRecord struct {
}

type Error

type Error struct {
	Message string `json:"error"`
	Code    int    `json:"code"`
}

func (*Error) Error

func (e *Error) Error() string

type ListOption

type ListOption struct {
	// contains filtered or unexported fields
}

Used by the Domain and Alias List methods to filter additional results.

Due to the nature of the ImprovMX REST API, users must use the provided methods to set the ListOption. However, the Alias.List method might still error if the SetLimit method has been called.

func NewListOption

func NewListOption() *ListOption

func (*ListOption) ClearIsActive

func (option *ListOption) ClearIsActive() *ListOption

Clears the value provided by SetIsActive

func (*ListOption) ClearLimit

func (option *ListOption) ClearLimit() *ListOption

Clears the value provided by SetLimit

func (*ListOption) ClearPage

func (option *ListOption) ClearPage() *ListOption

Clears the value provided by SetPage

func (*ListOption) ClearStartsWith

func (option *ListOption) ClearStartsWith() *ListOption

Clears the value provided by SetStartsWith

func (*ListOption) SetIsActive

func (option *ListOption) SetIsActive(value bool) *ListOption

Used to return only active or inactive domains. If unset, List methods will return all domains.

func (*ListOption) SetLimit

func (option *ListOption) SetLimit(value int) *ListOption

Number of domains to return. Defaults to 50, must be between 5 and 100. If this value is set when calling the Alias.List method, the method will fail with an error

func (*ListOption) SetPage

func (option *ListOption) SetPage(value int) *ListOption

Current page to load. Must be greater or equal to 1, otherwise List methods will fail with an error

func (*ListOption) SetStartsWith

func (option *ListOption) SetStartsWith(value string) *ListOption

Used to limit searches to domains or aliases that start with the provided string

type LogEntry

type LogEntry struct {
	CreatedAt  string     `json:"created"`
	CreatedRaw string     `json:"created_raw"`
	Events     []LogEvent `json:"events"`
	Address    Contact    `json:"forward"`
	Hostname   string     `json:"hostname"`
	ID         string     `json:"id"`
	MessageID  string     `json:"messageId"`
	Recipient  Contact    `json:"recipient"`
	Sender     Contact    `json:"sender"`
	Subject    string     `json:"subject"`
	Transport  string     `json:"transport"`
}

type LogEvent

type LogEvent struct {
	Code      int64         `json:"code"`
	CreatedAt string        `json:"created"`
	ID        string        `json:"id"`
	Local     string        `json:"local"`
	Message   string        `json:"message"`
	Server    string        `json:"server"`
	Status    MessageStatus `json:"status"`
}

type MessageStatus

type MessageStatus string

type Session

type Session struct {
	Credentials *CredentialEndpoint
	Account     *AccountEndpoint
	Domains     *DomainEndpoint
	Aliases     *AliasEndpoint
	// contains filtered or unexported fields
}

func New

func New(token string, options ...SessionOption) (*Session, error)

type SessionOption

type SessionOption func(*Session) error

func WithBaseURL

func WithBaseURL(url string) SessionOption

Sets the Base URL to query. This is typically BaseURLv3, however for both testing and possible future sandboxing support, this option is provided.

func WithClient

func WithClient(client *doze.Client) SessionOption

Sets the session client directly. This is provided for extreme user needs. However, the resty.Client.SetError type is still set to Error, and the host url is set toe BaseURLv3. Use WithBaseURL after calling WithClient if overriding the Host URL is required.

func WithDebug

func WithDebug() SessionOption

Enables the debug mode on the Session's internal http client

func WithUserAgent

func WithUserAgent(agent string) SessionOption

Sets the User-Agent to the given string on the session. By default, this is unset.

type Time

type Time = doze.Time

type User

type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type Whitelabel

type Whitelabel struct {
	Name string `json:"name"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL