Client API
The Client is the main entry point for interacting with the VaultSandbox Gateway. It handles authentication, inbox creation, and provides utility methods for managing inboxes.
Constants
Section titled “Constants”TTL (time-to-live) constants for inbox creation:
const ( MinTTL = 60 * time.Second // Minimum TTL: 1 minute MaxTTL = 604800 * time.Second // Maximum TTL: 7 days)Constructor
Section titled “Constructor”func New(apiKey string, opts ...Option) (*Client, error)Creates a new VaultSandbox client instance.
Options
Section titled “Options”Configuration options for the client using the functional options pattern.
// Available optionsWithBaseURL(url string) OptionWithHTTPClient(client *http.Client) OptionWithDeliveryStrategy(strategy DeliveryStrategy) OptionWithTimeout(timeout time.Duration) OptionWithRetries(count int) OptionWithRetryOn(statusCodes []int) OptionWithOnSyncError(fn func(error)) OptionOption Functions
Section titled “Option Functions”| Option | Type | Default | Description |
|---|---|---|---|
WithBaseURL | string | https://api.vaultsandbox.com | Gateway URL |
WithHTTPClient | *http.Client | Default client | Custom HTTP client |
WithDeliveryStrategy | DeliveryStrategy | StrategySSE | Email delivery strategy |
WithTimeout | time.Duration | 60s | Request timeout |
WithRetries | int | 3 | Maximum retry attempts for HTTP requests |
WithRetryOn | []int | [408, 429, 500, 502, 503, 504] | HTTP status codes that trigger a retry |
WithOnSyncError | func(error) | nil | Callback for background sync errors |
Polling Configuration Options
Section titled “Polling Configuration Options”For advanced control over polling behavior, use WithPollingConfig:
// Polling configuration structtype PollingConfig struct { InitialInterval time.Duration // Starting polling interval (default: 2s) MaxBackoff time.Duration // Maximum polling interval (default: 30s) BackoffMultiplier float64 // Interval multiplier after no changes (default: 1.5) JitterFactor float64 // Randomness factor to prevent synchronized polling (default: 0.3)}
WithPollingConfig(cfg PollingConfig) Option| Field | Type | Default | Description |
|---|---|---|---|
InitialInterval | time.Duration | 2s | Starting polling interval |
MaxBackoff | time.Duration | 30s | Maximum polling interval after backoff |
BackoffMultiplier | float64 | 1.5 | Multiplier for interval after each poll with no changes |
JitterFactor | float64 | 0.3 | Random jitter factor (30%) to prevent synchronized polling |
Delivery Strategies
Section titled “Delivery Strategies”const ( StrategySSE DeliveryStrategy = "sse" // Server-Sent Events (default) StrategyPolling DeliveryStrategy = "polling" // Periodic polling)Example
Section titled “Example”package main
import ( "os" "time"
vaultsandbox "github.com/vaultsandbox/client-go")
func main() { client, err := vaultsandbox.New( os.Getenv("VAULTSANDBOX_API_KEY"), vaultsandbox.WithBaseURL("https://api.vaultsandbox.com"), // SSE is the default strategy, no need to specify vaultsandbox.WithRetries(5), vaultsandbox.WithTimeout(30*time.Second), ) if err != nil { panic(err) } defer client.Close()}Methods
Section titled “Methods”CreateInbox
Section titled “CreateInbox”Creates a new email inbox with automatic key generation and encryption setup.
func (c *Client) CreateInbox(ctx context.Context, opts ...InboxOption) (*Inbox, error)Parameters
Section titled “Parameters”ctx: Context for cancellation and timeoutsopts(optional): Configuration options for the inbox
// Available inbox optionsWithTTL(ttl time.Duration) InboxOptionWithEmailAddress(email string) InboxOptionWithEmailAuth(enabled bool) InboxOptionWithEncryption(mode EncryptionMode) InboxOption| Option | Type | Description |
|---|---|---|
WithTTL | time.Duration | Time-to-live for the inbox (min: 60s, max: 7 days, default: 1 hour) |
WithEmailAddress | string | Request a specific email address (e.g., test@inbox.vaultsandbox.com) |
WithEmailAuth | bool | Enable/disable email authentication checks (SPF/DKIM/DMARC/PTR) |
WithEncryption | EncryptionMode | Request encrypted or plain inbox (EncryptionModeEncrypted, EncryptionModePlain) |
Encryption Mode
Section titled “Encryption Mode”type EncryptionMode string
const ( EncryptionModeDefault EncryptionMode = "" // Use server default EncryptionModeEncrypted EncryptionMode = "encrypted" // Request encrypted inbox EncryptionModePlain EncryptionMode = "plain" // Request plain inbox)Returns
Section titled “Returns”*Inbox- The created inbox instanceerror- Any error that occurred
Example
Section titled “Example”ctx := context.Background()
// Create inbox with default settingsinbox, err := client.CreateInbox(ctx)if err != nil { log.Fatal(err)}fmt.Println(inbox.EmailAddress())
// Create inbox with custom TTL (1 hour)inbox, err := client.CreateInbox(ctx, vaultsandbox.WithTTL(time.Hour))
// Request specific email addressinbox, err := client.CreateInbox(ctx, vaultsandbox.WithEmailAddress("mytest@inbox.vaultsandbox.com"),)
// Create inbox with email authentication disabledinbox, err := client.CreateInbox(ctx, vaultsandbox.WithEmailAuth(false))
// Create a plain (unencrypted) inbox (when server policy allows)inbox, err := client.CreateInbox(ctx, vaultsandbox.WithEncryption(vaultsandbox.EncryptionModePlain))Errors
Section titled “Errors”ErrUnauthorized- Invalid API keyErrInboxAlreadyExists- Requested email address or KEM public key is already in use*NetworkError- Network connection failure*APIError- API-level error (invalid request, permission denied)- 400:
clientKemPk is required when encryption is enabled - 409:
An inbox with the same client KEM public key already exists(encrypted inboxes) - 409:
An inbox with this email address already exists(plain inboxes)
- 400:
DeleteAllInboxes
Section titled “DeleteAllInboxes”Deletes all inboxes associated with the current API key. Useful for cleanup in test environments.
func (c *Client) DeleteAllInboxes(ctx context.Context) (int, error)Returns
Section titled “Returns”int- Number of inboxes deletederror- Any error that occurred
Example
Section titled “Example”deleted, err := client.DeleteAllInboxes(ctx)if err != nil { log.Fatal(err)}fmt.Printf("Deleted %d inboxes\n", deleted)Best Practice
Section titled “Best Practice”Use this in test cleanup to avoid orphaned inboxes:
func TestMain(m *testing.M) { // Setup client, _ := vaultsandbox.New(os.Getenv("VAULTSANDBOX_API_KEY"))
code := m.Run()
// Cleanup deleted, _ := client.DeleteAllInboxes(context.Background()) if deleted > 0 { log.Printf("Cleaned up %d orphaned inboxes\n", deleted) } client.Close()
os.Exit(code)}ServerInfo
Section titled “ServerInfo”Returns information about the VaultSandbox Gateway server. This information is fetched once during client initialization.
func (c *Client) ServerInfo() *ServerInfoReturns
Section titled “Returns”*ServerInfo - Server information struct
type ServerInfo struct { AllowedDomains []string MaxTTL time.Duration DefaultTTL time.Duration EncryptionPolicy EncryptionPolicy}| Field | Type | Description |
|---|---|---|
AllowedDomains | []string | List of domains allowed for inbox creation |
MaxTTL | time.Duration | Maximum time-to-live for inboxes |
DefaultTTL | time.Duration | Default time-to-live for inboxes |
EncryptionPolicy | EncryptionPolicy | Server’s encryption policy for inboxes |
Encryption Policy
Section titled “Encryption Policy”type EncryptionPolicy string
const ( EncryptionPolicyAlways EncryptionPolicy = "always" // All inboxes encrypted, no override EncryptionPolicyEnabled EncryptionPolicy = "enabled" // Encrypted by default, can request plain EncryptionPolicyDisabled EncryptionPolicy = "disabled" // Plain by default, can request encrypted EncryptionPolicyNever EncryptionPolicy = "never" // All inboxes plain, no override)| Policy | Default Encryption | Per-Inbox Override |
|---|---|---|
always | Encrypted | No - all inboxes encrypted |
enabled | Encrypted | Yes - can request plain |
disabled | Plain | Yes - can request encrypted |
never | Plain | No - all inboxes plain |
Helper Methods:
// CanOverride returns true if the policy allows per-inbox encryption overridefunc (p EncryptionPolicy) CanOverride() bool
// DefaultEncrypted returns true if encryption is the default for this policyfunc (p EncryptionPolicy) DefaultEncrypted() boolExample
Section titled “Example”info := client.ServerInfo()fmt.Printf("Max TTL: %v, Default TTL: %v\n", info.MaxTTL, info.DefaultTTL)fmt.Printf("Allowed domains: %v\n", info.AllowedDomains)fmt.Printf("Encryption policy: %s\n", info.EncryptionPolicy)
// Check if we can override encryption settingsif info.EncryptionPolicy.CanOverride() { fmt.Println("Per-inbox encryption override is allowed")}
// Check default encryption stateif info.EncryptionPolicy.DefaultEncrypted() { fmt.Println("Inboxes are encrypted by default")}CheckKey
Section titled “CheckKey”Validates the API key with the server.
func (c *Client) CheckKey(ctx context.Context) errorReturns
Section titled “Returns”error-nilif the API key is valid, otherwise an error
Example
Section titled “Example”if err := client.CheckKey(ctx); err != nil { log.Fatal("Invalid API key:", err)}Useful for verifying configuration before running tests:
func TestMain(m *testing.M) { client, err := vaultsandbox.New(os.Getenv("VAULTSANDBOX_API_KEY")) if err != nil { log.Fatal(err) }
if err := client.CheckKey(context.Background()); err != nil { log.Fatal("VaultSandbox API key is invalid:", err) }
os.Exit(m.Run())}WatchInboxes
Section titled “WatchInboxes”Returns a channel that receives events from multiple inboxes. The channel closes when the context is cancelled.
func (c *Client) WatchInboxes(ctx context.Context, inboxes ...*Inbox) <-chan *InboxEventParameters
Section titled “Parameters”ctx: Context for cancellation - when cancelled, the channel closes and all watchers are cleaned upinboxes: Variadic list of inbox instances to watch
Returns
Section titled “Returns”<-chan *InboxEvent- Receive-only channel of inbox events
InboxEvent Type
Section titled “InboxEvent Type”type InboxEvent struct { Inbox *Inbox // The inbox that received the email Email *Email // The received email}Example
Section titled “Example”inbox1, _ := client.CreateInbox(ctx)inbox2, _ := client.CreateInbox(ctx)
watchCtx, cancel := context.WithTimeout(ctx, 5*time.Minute)defer cancel()
for event := range client.WatchInboxes(watchCtx, inbox1, inbox2) { fmt.Printf("New email in %s: %s\n", event.Inbox.EmailAddress(), event.Email.Subject)}Behavior
Section titled “Behavior”- Returns immediately closed channel if no inboxes provided
- Channel has buffer size of 16
- Non-blocking sends: if channel buffer is full, events may be dropped
- All internal goroutines and watchers are cleaned up when context is cancelled
See Real-time Monitoring Guide for more details.
WatchInboxesFunc
Section titled “WatchInboxesFunc”Calls a callback function for each event from multiple inboxes until the context is cancelled. This is a convenience wrapper around WatchInboxes for simpler use cases where you don’t need channel semantics.
func (c *Client) WatchInboxesFunc(ctx context.Context, fn func(*InboxEvent), inboxes ...*Inbox)Parameters
Section titled “Parameters”ctx: Context for cancellation - when cancelled, watching stopsfn: Callback function called for each new eventinboxes: Variadic list of inbox instances to watch
Example
Section titled “Example”ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)defer cancel()
client.WatchInboxesFunc(ctx, func(event *vaultsandbox.InboxEvent) { fmt.Printf("Email in %s: %s\n", event.Inbox.EmailAddress(), event.Email.Subject)
// Route based on inbox switch event.Inbox.EmailAddress() { case "alerts@example.com": handleAlert(event.Email) default: handleGeneral(event.Email) }}, inbox1, inbox2, inbox3)Behavior
Section titled “Behavior”- Blocks until context is cancelled
- Each event is passed to the callback function
- Uses
WatchInboxesinternally with proper context handling
When to Use
Section titled “When to Use”Use WatchInboxesFunc instead of WatchInboxes when:
- You prefer callback-style processing over channel iteration
- You want simpler code without channel select statements
- You’re processing events in a blocking manner
GetInbox
Section titled “GetInbox”Retrieves an inbox by its email address from the client’s managed inboxes.
func (c *Client) GetInbox(emailAddress string) (*Inbox, bool)Parameters
Section titled “Parameters”emailAddress: The email address of the inbox to retrieve
Returns
Section titled “Returns”*Inbox- The inbox instance if foundbool-trueif the inbox was found,falseotherwise
Example
Section titled “Example”inbox, ok := client.GetInbox("test@inbox.vaultsandbox.com")if !ok { log.Fatal("Inbox not found")}fmt.Println(inbox.EmailAddress())Inboxes
Section titled “Inboxes”Returns all inboxes currently managed by the client.
func (c *Client) Inboxes() []*InboxReturns
Section titled “Returns”[]*Inbox - Slice of all managed inbox instances
Example
Section titled “Example”for _, inbox := range client.Inboxes() { fmt.Printf("Inbox: %s (expires: %v)\n", inbox.EmailAddress(), inbox.ExpiresAt())}DeleteInbox
Section titled “DeleteInbox”Deletes a specific inbox by its email address.
func (c *Client) DeleteInbox(ctx context.Context, emailAddress string) errorParameters
Section titled “Parameters”ctx: Context for cancellation and timeoutsemailAddress: The email address of the inbox to delete
Returns
Section titled “Returns”error- Any error that occurred
Example
Section titled “Example”err := client.DeleteInbox(ctx, "test@inbox.vaultsandbox.com")if err != nil { log.Fatal(err)}ExportInboxToFile
Section titled “ExportInboxToFile”Exports an inbox to a JSON file on disk. The exported data includes sensitive key material and should be treated as confidential.
func (c *Client) ExportInboxToFile(inbox *Inbox, filePath string) errorParameters
Section titled “Parameters”inbox: Inbox instance to exportfilePath: Path where the JSON file will be written
Returns
Section titled “Returns”error- Any error that occurred
Example
Section titled “Example”inbox, _ := client.CreateInbox(ctx)
// Export to fileerr := client.ExportInboxToFile(inbox, "./backup/inbox.json")if err != nil { log.Fatal(err)}
fmt.Println("Inbox exported to ./backup/inbox.json")Security Warning
Section titled “Security Warning”Exported data contains private encryption keys. Store securely and never commit to version control.
ImportInbox
Section titled “ImportInbox”Imports a previously exported inbox, restoring all data and encryption keys.
func (c *Client) ImportInbox(ctx context.Context, data *ExportedInbox) (*Inbox, error)Parameters
Section titled “Parameters”ctx: Context for cancellation and timeoutsdata: Previously exported inbox data
Returns
Section titled “Returns”*Inbox- The imported inbox instanceerror- Any error that occurred
ExportedInbox Type
Section titled “ExportedInbox Type”type ExportedInbox struct { Version int `json:"version"` EmailAddress string `json:"emailAddress"` ExpiresAt time.Time `json:"expiresAt"` InboxHash string `json:"inboxHash"` ServerSigPk string `json:"serverSigPk,omitempty"` // Only present for encrypted inboxes SecretKey string `json:"secretKey,omitempty"` // Only present for encrypted inboxes ExportedAt time.Time `json:"exportedAt"` EmailAuth bool `json:"emailAuth"` Encrypted bool `json:"encrypted"`}Example
Section titled “Example”// Load exported datadata, _ := os.ReadFile("./backup/inbox.json")
var exportedData vaultsandbox.ExportedInboxjson.Unmarshal(data, &exportedData)
inbox, err := client.ImportInbox(ctx, &exportedData)if err != nil { log.Fatal(err)}
fmt.Printf("Imported inbox: %s\n", inbox.EmailAddress())
// Use inbox normallyemails, _ := inbox.GetEmails(ctx)Errors
Section titled “Errors”ErrInboxAlreadyExists- Inbox is already imported in this clientErrInvalidImportData- Import data is invalid or corrupted*APIError- Server rejected the import (inbox may not exist)
ImportInboxFromFile
Section titled “ImportInboxFromFile”Imports an inbox from a JSON file.
func (c *Client) ImportInboxFromFile(ctx context.Context, filePath string) (*Inbox, error)Parameters
Section titled “Parameters”ctx: Context for cancellation and timeoutsfilePath: Path to the exported inbox JSON file
Returns
Section titled “Returns”*Inbox- The imported inbox instanceerror- Any error that occurred
Example
Section titled “Example”// Import from fileinbox, err := client.ImportInboxFromFile(ctx, "./backup/inbox.json")if err != nil { log.Fatal(err)}
fmt.Printf("Imported inbox: %s\n", inbox.EmailAddress())
// Watch for new emailswatchCtx, cancel := context.WithTimeout(ctx, 5*time.Minute)defer cancel()
for email := range inbox.Watch(watchCtx) { fmt.Printf("New email: %s\n", email.Subject)}Use Cases
Section titled “Use Cases”- Test reproducibility across runs
- Sharing inboxes between environments
- Manual testing workflows
- Debugging production issues
Closes the client, terminates any active SSE or polling connections, and cleans up resources.
func (c *Client) Close() errorReturns
Section titled “Returns”error- Any error that occurred during cleanup
Example
Section titled “Example”client, _ := vaultsandbox.New(apiKey)
defer client.Close()
inbox, _ := client.CreateInbox(ctx)// Use inbox...Best Practice
Section titled “Best Practice”Always close the client when done, especially in long-running processes:
var client *vaultsandbox.Client
func TestMain(m *testing.M) { var err error client, err = vaultsandbox.New(os.Getenv("VAULTSANDBOX_API_KEY")) if err != nil { log.Fatal(err) }
code := m.Run()
client.Close() os.Exit(code)}Errors
Section titled “Errors”The client package exports sentinel errors for use with errors.Is() checks, as well as error types for detailed error handling.
Sentinel Errors
Section titled “Sentinel Errors”var ( ErrMissingAPIKey error // No API key provided ErrClientClosed error // Operations attempted on a closed client ErrUnauthorized error // Invalid or expired API key ErrInboxNotFound error // Inbox not found ErrEmailNotFound error // Email not found ErrInboxAlreadyExists error // Inbox already exists (import conflict) ErrInvalidImportData error // Invalid or corrupted import data ErrDecryptionFailed error // Email decryption failed ErrSignatureInvalid error // Signature verification failed ErrRateLimited error // API rate limit exceeded)Example
Section titled “Example”inbox, err := client.CreateInbox(ctx)if errors.Is(err, vaultsandbox.ErrUnauthorized) { log.Fatal("Invalid API key")}if errors.Is(err, vaultsandbox.ErrRateLimited) { log.Println("Rate limited, retrying...")}Error Types
Section titled “Error Types”APIError
Section titled “APIError”Represents an HTTP error from the VaultSandbox API.
type APIError struct { StatusCode int // HTTP status code Message string // Error message from server RequestID string // Request ID for support}NetworkError
Section titled “NetworkError”Represents a network-level failure.
type NetworkError struct { Err error // Underlying network error}SignatureVerificationError
Section titled “SignatureVerificationError”Indicates signature verification failed, including potential server key mismatch (MITM detection).
type SignatureVerificationError struct { Message string}ResourceType
Section titled “ResourceType”Used to identify which resource type an error relates to:
type ResourceType string
const ( ResourceUnknown ResourceType = "" // Resource type not specified ResourceInbox ResourceType = "inbox" // Error relates to an inbox ResourceEmail ResourceType = "email" // Error relates to an email)Example: Type Assertions
Section titled “Example: Type Assertions”email, err := inbox.GetEmail(ctx, emailID)if err != nil { var apiErr *vaultsandbox.APIError if errors.As(err, &apiErr) { log.Printf("API error %d: %s (request: %s)", apiErr.StatusCode, apiErr.Message, apiErr.RequestID) }
var netErr *vaultsandbox.NetworkError if errors.As(err, &netErr) { log.Printf("Network error: %v", netErr.Err) }}Complete Example
Section titled “Complete Example”Here’s a complete example showing typical client usage:
package main
import ( "context" "fmt" "log" "os" "regexp" "time"
vaultsandbox "github.com/vaultsandbox/client-go")
func main() { ctx := context.Background()
// Create client client, err := vaultsandbox.New( os.Getenv("VAULTSANDBOX_API_KEY"), vaultsandbox.WithBaseURL(os.Getenv("VAULTSANDBOX_URL")), // SSE is the default strategy vaultsandbox.WithRetries(5), ) if err != nil { log.Fatal(err) } defer client.Close()
// Verify API key if err := client.CheckKey(ctx); err != nil { log.Fatal("Invalid API key:", err) }
// Get server info info := client.ServerInfo() fmt.Printf("Connected to VaultSandbox (default TTL: %v)\n", info.DefaultTTL)
// Create inbox inbox, err := client.CreateInbox(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Created inbox: %s\n", inbox.EmailAddress())
// Export for later use if err := client.ExportInboxToFile(inbox, "./inbox-backup.json"); err != nil { log.Fatal(err) }
// Wait for email email, err := inbox.WaitForEmail(ctx, vaultsandbox.WithWaitTimeout(30*time.Second), vaultsandbox.WithSubjectRegex(regexp.MustCompile(`Test`)), ) if err != nil { log.Fatal(err) }
fmt.Printf("Received: %s\n", email.Subject)
// Clean up if err := inbox.Delete(ctx); err != nil { log.Fatal(err) }
// Delete any other orphaned inboxes deleted, err := client.DeleteAllInboxes(ctx) if err != nil { log.Fatal(err) } fmt.Printf("Cleaned up %d total inboxes\n", deleted)}Next Steps
Section titled “Next Steps”- Inbox API Reference - Learn about inbox methods
- Email API Reference - Work with email objects
- Error Handling - Handle errors gracefully
- Import/Export Guide - Advanced import/export usage