provider

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Mar 6, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

provider-kit

Go Reference Go Report Card License codecov

中文文档

A lightweight, extensible Go library for sending messages (email, SMS, DingTalk, etc.) through pluggable providers with built-in retry, idempotency, and error normalization.

Features

  • Provider Interface - Clean interface for implementing custom message providers
  • Registry Pattern - Centralized provider management with channel-based routing
  • Built-in Providers - SMTP for email, HTTP API for external services (SMS, DingTalk, etc.)
  • Automatic Retry - Configurable retry logic with exponential backoff
  • Idempotency Support - Prevent duplicate sends with idempotency keys
  • Error Normalization - Unified error handling across different providers
  • Template Support - Simple template rendering with multi-language support
  • Factory Pattern - Create providers from configuration maps

Installation

go get github.com/soulteary/provider-kit

Quick Start

Basic Usage
import provider "github.com/soulteary/provider-kit"

// Create a registry
registry := provider.NewRegistry()

// Create and register an SMTP provider
smtpProvider, err := provider.NewSMTPProvider(&provider.SMTPConfig{
    Host:     "smtp.example.com",
    Port:     587,
    Username: "user@example.com",
    Password: "password",
    From:     "noreply@example.com",
})
if err != nil {
    log.Fatal(err)
}

if err := registry.Register(smtpProvider); err != nil {
    log.Fatal(err)
}

// Create and send a message
msg := provider.NewMessage("recipient@example.com").
    WithSubject("Hello").
    WithBody("This is a test email.")

result, err := registry.Send(context.Background(), provider.ChannelEmail, msg)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Message sent: %s\n", result.MessageID)
With Retry Support
import provider "github.com/soulteary/provider-kit"

// Wrap provider with retry
retryProvider := provider.NewRetryProvider(smtpProvider, &provider.RetryConfig{
    MaxRetries:        3,
    RetryDelay:        100 * time.Millisecond,
    MaxRetryDelay:     5 * time.Second,
    BackoffMultiplier: 2.0,
    RetryableReasons: []provider.ErrorReason{
        provider.ReasonProviderDown,
        provider.ReasonTimeout,
        provider.ReasonRateLimited,
    },
})

registry.Register(retryProvider)
With Idempotency Support
import provider "github.com/soulteary/provider-kit"

// Wrap provider with idempotency
idempotentProvider := provider.NewIdempotentProvider(smtpProvider, &provider.IdempotencyConfig{
    Store: provider.NewMemoryIdempotencyStore(),
    TTL:   5 * time.Minute,
})

registry.Register(idempotentProvider)

// Send with idempotency key
msg := provider.NewMessage("recipient@example.com").
    WithBody("Important message").
    WithIdempotencyKey("unique-key-123")

// Second send with same key will return cached result
result, _ := registry.Send(ctx, provider.ChannelEmail, msg)
HTTP API Provider
import provider "github.com/soulteary/provider-kit"

// Create HTTP provider for external SMS API
httpProvider, err := provider.NewHTTPProvider(&provider.HTTPConfig{
    BaseURL:      "https://api.sms-provider.com",
    SendEndpoint: "/v1/send",
    APIKey:       "your-api-key",
    ChannelType:  provider.ChannelSMS,
    ProviderName: "sms-provider",
})
if err != nil {
    log.Fatal(err)
}

registry.Register(httpProvider)
Verification Code Messages
import provider "github.com/soulteary/provider-kit"

// Build verification message with locale support
msg := provider.BuildVerificationMessage(
    "user@example.com",
    "123456",
    "zh-CN",
    provider.ChannelEmail,
)

// Send verification email
result, err := registry.Send(ctx, provider.ChannelEmail, msg)
Provider Factory
import provider "github.com/soulteary/provider-kit"

// Register factory
registry.RegisterFactory("smtp", provider.SMTPProviderFactory)

// Create provider from config map
config := map[string]string{
    "host":     "smtp.example.com",
    "port":     "587",
    "username": "user",
    "password": "pass",
    "from":     "noreply@example.com",
}

smtpProvider, err := registry.CreateProvider("smtp", config)

API Reference

Channel Types
Channel Description
ChannelSMS SMS message channel
ChannelEmail Email message channel
ChannelHTTP Generic HTTP API channel (for external SMS, DingTalk, etc.)
ChannelDingTalk DingTalk work notification channel (via herald-dingtalk HTTP service)
Provider Interface
type Provider interface {
    Send(ctx context.Context, msg *Message) (*SendResult, error)
    Channel() Channel
    Name() string
    Validate() error
}
Message Options
Method Description
WithSubject(s) Set message subject (email)
WithBody(s) Set message body
WithTemplate(s) Set template name
WithParams(map) Set template parameters
WithCode(s) Set verification code
WithLocale(s) Set locale for formatting
WithIdempotencyKey(s) Set idempotency key
AddMetadata(k, v) Add metadata entry
Error Reasons
Reason Description
ReasonSendFailed Send operation failed
ReasonProviderDown Provider is unavailable
ReasonInvalidConfig Invalid configuration
ReasonRateLimited Rate limited by provider
ReasonInvalidDestination Invalid recipient
ReasonTimeout Request timed out
ReasonUnauthorized Authentication failed
ReasonNotRegistered No provider registered
ReasonIdempotencyConflict Idempotency conflict
SMTP Configuration
Option Type Default Description
Host string Required SMTP server host
Port int 587 SMTP server port
Username string "" Authentication username
Password string "" Authentication password
From string Required Sender email address
FromName string "" Sender display name
UseTLS bool false Use direct TLS connection
UseStartTLS bool true Use STARTTLS
SkipTLSVerify bool false Skip TLS verification
Timeout time.Duration 30s Connection timeout
Retry Configuration
Option Type Default Description
MaxRetries int 3 Maximum retry attempts
RetryDelay time.Duration 100ms Initial retry delay
MaxRetryDelay time.Duration 5s Maximum retry delay
BackoffMultiplier float64 2.0 Exponential backoff multiplier
RetryableReasons []ErrorReason [ProviderDown, Timeout, RateLimited] Errors that trigger retry

Project Structure

provider-kit/
├── channel.go          # Channel type definitions
├── channel_test.go
├── errors.go           # Error types and normalization
├── errors_test.go
├── http.go             # HTTP API provider
├── http_test.go
├── idempotency.go      # Idempotency support
├── idempotency_test.go
├── interface.go        # Provider interface definitions
├── message.go          # Message type
├── message_test.go
├── registry.go         # Provider registry
├── registry_test.go
├── result.go           # Send result type
├── result_test.go
├── retry.go            # Retry logic
├── retry_test.go
├── smtp.go             # SMTP provider
├── smtp_test.go
├── template.go         # Template utilities
├── template_test.go
├── go.mod
└── LICENSE

Implementing Custom Providers

type MyCustomProvider struct {
    config MyConfig
}

func (p *MyCustomProvider) Send(ctx context.Context, msg *provider.Message) (*provider.SendResult, error) {
    // Implement your send logic
    if err := p.doSend(msg); err != nil {
        return provider.NewFailureResult(p.Name(), p.Channel(), 
            provider.ErrSendFailed("send failed", err)), err
    }
    return provider.NewSuccessResult(p.Name(), p.Channel(), "msg-id"), nil
}

func (p *MyCustomProvider) Channel() provider.Channel {
    return provider.ChannelSMS
}

func (p *MyCustomProvider) Name() string {
    return "my-custom"
}

func (p *MyCustomProvider) Validate() error {
    if p.config.APIKey == "" {
        return provider.ErrInvalidConfig("API key is required")
    }
    return nil
}

Test Coverage

Run tests with coverage:

go test -coverprofile=coverage.out ./...
go tool cover -func=coverage.out

Requirements

  • Go 1.21 or later

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FormatVerificationEmail

func FormatVerificationEmail(code string, locale string) (subject, body string)

FormatVerificationEmail formats a verification code email (expiry fixed at 5 minutes). Returns subject and body based on locale. Use FormatVerificationEmailWithMinutes for custom expiry.

func FormatVerificationEmailWithMinutes added in v1.1.0

func FormatVerificationEmailWithMinutes(code string, locale string, minutes int) (subject, body string)

FormatVerificationEmailWithMinutes formats a verification code email with custom expiry in minutes. Returns subject and body based on locale. Used by Herald template when purpose is "login".

func FormatVerificationSMS

func FormatVerificationSMS(code string, locale string) string

FormatVerificationSMS formats a verification code SMS (expiry fixed at 5 minutes). Use FormatVerificationSMSWithMinutes for custom expiry.

func FormatVerificationSMSWithMinutes added in v1.1.0

func FormatVerificationSMSWithMinutes(code string, locale string, minutes int) string

FormatVerificationSMSWithMinutes formats a verification code SMS with custom expiry in minutes. Used by Herald template when purpose is "login".

func IsProviderError

func IsProviderError(err error) bool

IsProviderError checks if the error is a ProviderError

func RegisterGlobal

func RegisterGlobal(provider Provider) error

RegisterGlobal registers a provider in the global registry

Types

type Channel

type Channel string

Channel represents the delivery channel type

const (
	// ChannelSMS represents SMS delivery channel
	ChannelSMS Channel = "sms"
	// ChannelEmail represents email delivery channel
	ChannelEmail Channel = "email"
	// ChannelHTTP represents generic HTTP API channel (for extensibility)
	ChannelHTTP Channel = "http"
	// ChannelDingTalk represents DingTalk work notification (via herald-dingtalk HTTP service)
	ChannelDingTalk Channel = "dingtalk"
)

func SupportedChannels

func SupportedChannels() []Channel

SupportedChannels returns all supported channels

func (Channel) IsValid

func (c Channel) IsValid() bool

IsValid checks if the channel is a valid known channel type

func (Channel) String

func (c Channel) String() string

String returns the string representation of the channel

type DefaultSMTPDialer

type DefaultSMTPDialer struct{}

DefaultSMTPDialer uses the standard library for SMTP

type ErrorReason

type ErrorReason string

Error reason codes for provider operations

const (
	// ReasonSendFailed indicates the send operation failed
	ReasonSendFailed ErrorReason = "send_failed"
	// ReasonProviderDown indicates the provider is unavailable
	ReasonProviderDown ErrorReason = "provider_down"
	// ReasonInvalidConfig indicates invalid provider configuration
	ReasonInvalidConfig ErrorReason = "invalid_config"
	// ReasonRateLimited indicates the provider rate limited the request
	ReasonRateLimited ErrorReason = "rate_limited"
	// ReasonInvalidDestination indicates the destination is invalid
	ReasonInvalidDestination ErrorReason = "invalid_destination"
	// ReasonTimeout indicates the request timed out
	ReasonTimeout ErrorReason = "timeout"
	// ReasonUnauthorized indicates authentication failed
	ReasonUnauthorized ErrorReason = "unauthorized"
	// ReasonNotRegistered indicates no provider is registered for the channel
	ReasonNotRegistered ErrorReason = "not_registered"
	// ReasonValidationFailed indicates provider validation failed
	ReasonValidationFailed ErrorReason = "validation_failed"
	// ReasonIdempotencyConflict indicates an idempotency conflict
	ReasonIdempotencyConflict ErrorReason = "idempotency_conflict"
)

func GetErrorReason

func GetErrorReason(err error) (ErrorReason, bool)

GetErrorReason extracts the error reason from a ProviderError

func (ErrorReason) String

func (r ErrorReason) String() string

String returns the string representation of the error reason

type HTTPConfig

type HTTPConfig struct {
	// BaseURL is the API base URL
	BaseURL string
	// SendEndpoint is the send endpoint path (default: /v1/send)
	SendEndpoint string
	// APIKey is the API key for authentication
	APIKey string
	// APIKeyHeader is the header name for API key (default: X-API-Key)
	APIKeyHeader string
	// Timeout is the request timeout
	Timeout time.Duration
	// Headers are additional headers to include in requests
	Headers map[string]string
	// ChannelType is the channel type this provider handles
	ChannelType Channel
	// ProviderName is the name of this provider instance
	ProviderName string
}

HTTPConfig contains HTTP API provider configuration

func DefaultHTTPConfig

func DefaultHTTPConfig() *HTTPConfig

DefaultHTTPConfig returns default HTTP configuration

func (*HTTPConfig) Validate

func (c *HTTPConfig) Validate() error

Validate validates the HTTP configuration

type HTTPProvider

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

HTTPProvider implements message sending via HTTP API This is a generic provider for external messaging APIs

func NewHTTPProvider

func NewHTTPProvider(config *HTTPConfig) (*HTTPProvider, error)

NewHTTPProvider creates a new HTTP API provider

func (*HTTPProvider) Channel

func (p *HTTPProvider) Channel() Channel

Channel returns the channel type

func (*HTTPProvider) Name

func (p *HTTPProvider) Name() string

Name returns the provider name

func (*HTTPProvider) Send

func (p *HTTPProvider) Send(ctx context.Context, msg *Message) (*SendResult, error)

Send sends a message via HTTP API

func (*HTTPProvider) SetHTTPClient

func (p *HTTPProvider) SetHTTPClient(client *http.Client)

SetHTTPClient sets a custom HTTP client

func (*HTTPProvider) Validate

func (p *HTTPProvider) Validate() error

Validate checks if the provider is properly configured

type HTTPSendRequest

type HTTPSendRequest struct {
	Channel        string            `json:"channel"`
	To             string            `json:"to"`
	Template       string            `json:"template,omitempty"`
	Params         map[string]string `json:"params,omitempty"`
	Subject        string            `json:"subject,omitempty"`
	Body           string            `json:"body,omitempty"`
	Locale         string            `json:"locale,omitempty"`
	IdempotencyKey string            `json:"idempotency_key"`
	TimeoutSeconds int               `json:"timeout_seconds,omitempty"`
}

HTTPSendRequest is the request body for the HTTP send API

type HTTPSendResponse

type HTTPSendResponse struct {
	OK           bool   `json:"ok"`
	MessageID    string `json:"message_id,omitempty"`
	Provider     string `json:"provider,omitempty"`
	ErrorCode    string `json:"error_code,omitempty"`
	ErrorMessage string `json:"error_message,omitempty"`
}

HTTPSendResponse is the response body from the HTTP send API

type IdempotencyConfig

type IdempotencyConfig struct {
	// Store is the idempotency store (default: in-memory)
	Store IdempotencyStore
	// TTL is the cache TTL for idempotency records
	TTL time.Duration
}

IdempotencyConfig contains idempotency configuration

func DefaultIdempotencyConfig

func DefaultIdempotencyConfig() *IdempotencyConfig

DefaultIdempotencyConfig returns default idempotency configuration

type IdempotencyStore

type IdempotencyStore interface {
	// Get retrieves a cached result for the given key
	Get(ctx context.Context, key string) (*SendResult, bool, error)
	// Set stores a result with the given key and TTL
	Set(ctx context.Context, key string, result *SendResult, ttl time.Duration) error
	// Delete removes a cached result
	Delete(ctx context.Context, key string) error
}

IdempotencyStore defines the interface for storing idempotency records

type IdempotentProvider

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

IdempotentProvider wraps a provider with idempotency support

func NewIdempotentProvider

func NewIdempotentProvider(provider Provider, config *IdempotencyConfig) *IdempotentProvider

NewIdempotentProvider wraps a provider with idempotency support

func (*IdempotentProvider) Channel

func (p *IdempotentProvider) Channel() Channel

Channel returns the channel type

func (*IdempotentProvider) Name

func (p *IdempotentProvider) Name() string

Name returns the provider name

func (*IdempotentProvider) Send

func (p *IdempotentProvider) Send(ctx context.Context, msg *Message) (*SendResult, error)

Send sends a message with idempotency support

func (*IdempotentProvider) Validate

func (p *IdempotentProvider) Validate() error

Validate checks if the provider is properly configured

type MemoryIdempotencyStore

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

MemoryIdempotencyStore is an in-memory idempotency store

func NewMemoryIdempotencyStore

func NewMemoryIdempotencyStore() *MemoryIdempotencyStore

NewMemoryIdempotencyStore creates a new in-memory idempotency store

func (*MemoryIdempotencyStore) Delete

func (s *MemoryIdempotencyStore) Delete(ctx context.Context, key string) error

Delete removes a cached result

func (*MemoryIdempotencyStore) Get

Get retrieves a cached result for the given key

func (*MemoryIdempotencyStore) Set

func (s *MemoryIdempotencyStore) Set(ctx context.Context, key string, result *SendResult, ttl time.Duration) error

Set stores a result with the given key and TTL

type Message

type Message struct {
	// To is the recipient address (email address or phone number)
	To string

	// Subject is the message subject (primarily for email)
	Subject string

	// Body is the message body content
	Body string

	// Template is the template name/identifier (for templated messages)
	Template string

	// Params are template parameters/variables
	Params map[string]string

	// Code is the verification code (for OTP messages)
	Code string

	// Locale is the locale for message formatting (e.g., "en-US", "zh-CN")
	Locale string

	// IdempotencyKey is the key for idempotency (prevents duplicate sends)
	IdempotencyKey string

	// Metadata contains additional provider-specific data
	Metadata map[string]string
}

Message represents a message to be sent via a provider

func BuildVerificationMessage

func BuildVerificationMessage(to, code, locale string, channel Channel) *Message

BuildVerificationMessage creates a verification code message

func NewMessage

func NewMessage(to string) *Message

NewMessage creates a new Message with the required destination

func (*Message) AddMetadata

func (m *Message) AddMetadata(key, value string) *Message

AddMetadata adds a single metadata entry

func (*Message) Clone

func (m *Message) Clone() *Message

Clone creates a deep copy of the message

func (*Message) String

func (m *Message) String() string

String returns a string representation (safe for logging, without sensitive data)

func (*Message) Validate

func (m *Message) Validate() error

Validate validates the message has required fields

func (*Message) WithBody

func (m *Message) WithBody(body string) *Message

WithBody sets the message body

func (*Message) WithCode

func (m *Message) WithCode(code string) *Message

WithCode sets the verification code

func (*Message) WithIdempotencyKey

func (m *Message) WithIdempotencyKey(key string) *Message

WithIdempotencyKey sets the idempotency key

func (*Message) WithLocale

func (m *Message) WithLocale(locale string) *Message

WithLocale sets the locale

func (*Message) WithMetadata

func (m *Message) WithMetadata(metadata map[string]string) *Message

WithMetadata sets additional metadata

func (*Message) WithParam

func (m *Message) WithParam(key, value string) *Message

WithParam adds a single template parameter

func (*Message) WithParams

func (m *Message) WithParams(params map[string]string) *Message

WithParams sets the template parameters

func (*Message) WithSubject

func (m *Message) WithSubject(subject string) *Message

WithSubject sets the message subject

func (*Message) WithTemplate

func (m *Message) WithTemplate(template string) *Message

WithTemplate sets the template name

type MultiChannelProvider

type MultiChannelProvider interface {
	Provider
	// Channels returns all channels this provider supports
	Channels() []Channel
}

MultiChannelProvider is a provider that supports multiple channels

type Provider

type Provider interface {
	// Send sends a message via the provider
	Send(ctx context.Context, msg *Message) (*SendResult, error)

	// Channel returns the channel type this provider supports
	Channel() Channel

	// Name returns the provider's name (e.g., "smtp", "aliyun", "twilio")
	Name() string

	// Validate checks if the provider is properly configured
	Validate() error
}

Provider is the interface for message providers

func GetGlobal

func GetGlobal(channel Channel) (Provider, error)

GetGlobal gets a provider from the global registry

func HTTPProviderFactory

func HTTPProviderFactory(config map[string]string) (Provider, error)

HTTPProviderFactory is the factory for HTTP providers

func NewHTTPProviderFromMap

func NewHTTPProviderFromMap(configMap map[string]string) (Provider, error)

NewHTTPProviderFromMap creates an HTTP provider from a configuration map

func NewSMTPProviderFromMap

func NewSMTPProviderFromMap(configMap map[string]string) (Provider, error)

NewSMTPProviderFromMap creates an SMTP provider from a configuration map

func SMTPProviderFactory

func SMTPProviderFactory(config map[string]string) (Provider, error)

SMTPProviderFactory is the factory for SMTP providers

func WrapWithIdempotency

func WrapWithIdempotency(provider Provider, store IdempotencyStore, ttl time.Duration) Provider

WrapWithIdempotency wraps a provider with idempotency support

func WrapWithRetry

func WrapWithRetry(provider Provider, maxRetries int, retryDelay time.Duration) Provider

WrapWithRetry wraps a provider with retry support

type ProviderError

type ProviderError struct {
	Reason       ErrorReason
	Message      string
	ProviderName string
	Channel      Channel
	Err          error // Underlying error
}

ProviderError represents a provider operation error

func ErrIdempotencyConflict

func ErrIdempotencyConflict(message string) *ProviderError

ErrIdempotencyConflict creates an idempotency conflict error

func ErrInvalidConfig

func ErrInvalidConfig(message string) *ProviderError

ErrInvalidConfig creates an invalid configuration error

func ErrInvalidDestination

func ErrInvalidDestination(message string) *ProviderError

ErrInvalidDestination creates an invalid destination error

func ErrNotRegistered

func ErrNotRegistered(channel Channel) *ProviderError

ErrNotRegistered creates a not registered error

func ErrProviderDown

func ErrProviderDown(message string, err error) *ProviderError

ErrProviderDown creates a provider unavailable error

func ErrRateLimited

func ErrRateLimited(message string) *ProviderError

ErrRateLimited creates a rate limited error

func ErrSendFailed

func ErrSendFailed(message string, err error) *ProviderError

ErrSendFailed creates a send failure error

func ErrTimeout

func ErrTimeout(message string, err error) *ProviderError

ErrTimeout creates a timeout error

func ErrUnauthorized

func ErrUnauthorized(message string) *ProviderError

ErrUnauthorized creates an unauthorized error

func ErrValidationFailed

func ErrValidationFailed(message string) *ProviderError

ErrValidationFailed creates a validation failed error

func NewProviderError

func NewProviderError(reason ErrorReason, message string) *ProviderError

NewProviderError creates a new ProviderError

func NormalizeError

func NormalizeError(err error, channel Channel, providerName string) *ProviderError

NormalizeError normalizes any error to a ProviderError

func (*ProviderError) Error

func (e *ProviderError) Error() string

Error implements the error interface

func (*ProviderError) Unwrap

func (e *ProviderError) Unwrap() error

Unwrap returns the underlying error

func (*ProviderError) WithError

func (e *ProviderError) WithError(err error) *ProviderError

WithError adds an underlying error

func (*ProviderError) WithProvider

func (e *ProviderError) WithProvider(name string, channel Channel) *ProviderError

WithProvider adds provider information to the error

type ProviderFactory

type ProviderFactory func(config map[string]string) (Provider, error)

ProviderFactory creates a provider instance

type Registry

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

Registry manages available providers

func GlobalRegistry

func GlobalRegistry() *Registry

GlobalRegistry returns the global registry instance

func NewRegistry

func NewRegistry() *Registry

NewRegistry creates a new provider registry

func (*Registry) Channels

func (r *Registry) Channels() []Channel

Channels returns all registered channels

func (*Registry) Clear

func (r *Registry) Clear()

Clear removes all registered providers and factories

func (*Registry) CreateProvider

func (r *Registry) CreateProvider(name string, config map[string]string) (Provider, error)

CreateProvider creates a provider using a registered factory

func (*Registry) Get

func (r *Registry) Get(channel Channel) (Provider, error)

Get returns a provider for the given channel

func (*Registry) GetProvider

func (r *Registry) GetProvider(channel Channel) (Provider, error)

GetProvider is an alias for Get (for backward compatibility)

func (*Registry) Has

func (r *Registry) Has(channel Channel) bool

Has checks if a provider is registered for a channel

func (*Registry) HasFactory

func (r *Registry) HasFactory(name string) bool

HasFactory checks if a factory is registered

func (*Registry) Providers

func (r *Registry) Providers() []Provider

Providers returns all registered providers

func (*Registry) Register

func (r *Registry) Register(provider Provider) error

Register registers a provider for its channel

func (*Registry) RegisterFactory

func (r *Registry) RegisterFactory(name string, factory ProviderFactory) error

RegisterFactory registers a provider factory by name

func (*Registry) Send

func (r *Registry) Send(ctx context.Context, channel Channel, msg *Message) (*SendResult, error)

Send sends a message using the appropriate provider for the channel

func (*Registry) Unregister

func (r *Registry) Unregister(channel Channel)

Unregister removes a provider for a channel

func (*Registry) UnregisterFactory

func (r *Registry) UnregisterFactory(name string)

UnregisterFactory removes a factory by name

type RetryConfig

type RetryConfig struct {
	// MaxRetries is the maximum number of retry attempts
	MaxRetries int
	// RetryDelay is the initial delay between retries
	RetryDelay time.Duration
	// MaxRetryDelay is the maximum delay between retries
	MaxRetryDelay time.Duration
	// BackoffMultiplier is the multiplier for exponential backoff
	BackoffMultiplier float64
	// RetryableReasons are error reasons that should trigger a retry
	RetryableReasons []ErrorReason
}

RetryConfig contains retry configuration

func DefaultRetryConfig

func DefaultRetryConfig() *RetryConfig

DefaultRetryConfig returns default retry configuration

func (*RetryConfig) CalculateDelay

func (c *RetryConfig) CalculateDelay(attempt int) time.Duration

CalculateDelay calculates the delay for the next retry attempt using exponential backoff

func (*RetryConfig) IsRetryable

func (c *RetryConfig) IsRetryable(err error) bool

IsRetryable checks if an error should trigger a retry

type RetryProvider

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

RetryProvider wraps a provider with retry support

func NewRetryProvider

func NewRetryProvider(provider Provider, config *RetryConfig) *RetryProvider

NewRetryProvider wraps a provider with retry support

func (*RetryProvider) Channel

func (p *RetryProvider) Channel() Channel

Channel returns the channel type

func (*RetryProvider) Name

func (p *RetryProvider) Name() string

Name returns the provider name

func (*RetryProvider) Send

func (p *RetryProvider) Send(ctx context.Context, msg *Message) (*SendResult, error)

Send sends a message with retry support

func (*RetryProvider) Validate

func (p *RetryProvider) Validate() error

Validate checks if the provider is properly configured

type RetrySender

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

RetrySender wraps a Sender with retry support

func NewRetrySender

func NewRetrySender(sender Sender, config *RetryConfig) *RetrySender

NewRetrySender wraps a sender with retry support

func (*RetrySender) Send

func (s *RetrySender) Send(ctx context.Context, channel Channel, msg *Message) (*SendResult, error)

Send sends a message with retry support

type SMTPClient

type SMTPClient interface {
	Auth(a interface{}) error
	Mail(from string) error
	Rcpt(to string) error
	Data() (interface {
		Write([]byte) (int, error)
		Close() error
	}, error)
	Quit() error
	Close() error
}

SMTPClient is the interface for SMTP client operations

type SMTPConfig

type SMTPConfig struct {
	// Host is the SMTP server host
	Host string
	// Port is the SMTP server port
	Port int
	// Username is the SMTP authentication username
	Username string
	// Password is the SMTP authentication password
	Password string
	// From is the sender email address
	From string
	// FromName is the sender display name (optional)
	FromName string
	// UseTLS enables TLS connection
	UseTLS bool
	// UseStartTLS enables STARTTLS
	UseStartTLS bool
	// SkipTLSVerify skips TLS certificate verification (not recommended)
	SkipTLSVerify bool
	// Timeout is the connection timeout
	Timeout time.Duration
}

SMTPConfig contains SMTP provider configuration

func DefaultSMTPConfig

func DefaultSMTPConfig() *SMTPConfig

DefaultSMTPConfig returns default SMTP configuration

func (*SMTPConfig) Validate

func (c *SMTPConfig) Validate() error

Validate validates the SMTP configuration

type SMTPDialer

type SMTPDialer interface {
	// DialPlain dials SMTP server without encryption
	DialPlain(addr string, auth interface{}, from string, to []string, body []byte) error
	// DialTLS dials SMTP server with TLS
	DialTLS(addr string, tlsConfig interface{}, host string) (SMTPClient, error)
	// DialStartTLS dials SMTP server and upgrades to TLS
	DialStartTLS(addr string, tlsConfig interface{}) (SMTPClient, error)
}

SMTPDialer is the interface for SMTP connection operations

type SMTPProvider

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

SMTPProvider implements email sending via SMTP

func NewSMTPProvider

func NewSMTPProvider(config *SMTPConfig) (*SMTPProvider, error)

NewSMTPProvider creates a new SMTP provider

func (*SMTPProvider) Channel

func (p *SMTPProvider) Channel() Channel

Channel returns the channel type

func (*SMTPProvider) Name

func (p *SMTPProvider) Name() string

Name returns the provider name

func (*SMTPProvider) Send

func (p *SMTPProvider) Send(ctx context.Context, msg *Message) (*SendResult, error)

Send sends an email via SMTP

func (*SMTPProvider) SetDialer

func (p *SMTPProvider) SetDialer(dialer SMTPDialer)

SetDialer sets a custom dialer for testing

func (*SMTPProvider) Validate

func (p *SMTPProvider) Validate() error

Validate checks if the provider is properly configured

type SendResult

type SendResult struct {
	// OK indicates if the send was successful
	OK bool

	// MessageID is the provider's message ID (if available)
	MessageID string

	// Provider is the name of the provider that handled the request
	Provider string

	// Channel is the channel used for sending
	Channel Channel

	// Timestamp is when the message was sent
	Timestamp time.Time

	// Metadata contains additional result data from the provider
	Metadata map[string]string

	// Error contains error details if OK is false
	Error *ProviderError
}

SendResult represents the result of a send operation

func NewFailureResult

func NewFailureResult(provider string, channel Channel, err *ProviderError) *SendResult

NewFailureResult creates a failed send result

func NewSuccessResult

func NewSuccessResult(provider string, channel Channel, messageID string) *SendResult

NewSuccessResult creates a successful send result

func SendGlobal

func SendGlobal(ctx context.Context, channel Channel, msg *Message) (*SendResult, error)

SendGlobal sends a message using the global registry

func (*SendResult) GetError

func (r *SendResult) GetError() error

GetError returns the error if the result is a failure

func (*SendResult) WithMetadata

func (r *SendResult) WithMetadata(key, value string) *SendResult

WithMetadata adds metadata to the result

type Sender

type Sender interface {
	// Send sends a message using the appropriate provider
	Send(ctx context.Context, channel Channel, msg *Message) (*SendResult, error)
}

Sender is a simplified interface for sending messages

type SimpleTemplateRenderer

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

SimpleTemplateRenderer is a simple template renderer using string replacement

func NewSimpleTemplateRenderer

func NewSimpleTemplateRenderer() *SimpleTemplateRenderer

NewSimpleTemplateRenderer creates a new simple template renderer

func (*SimpleTemplateRenderer) Render

func (r *SimpleTemplateRenderer) Render(template string, params map[string]string) (string, error)

Render renders a template with the given parameters

func (*SimpleTemplateRenderer) WithDelimiters

func (r *SimpleTemplateRenderer) WithDelimiters(left, right string) *SimpleTemplateRenderer

WithDelimiters sets custom delimiters

type TemplateRenderer

type TemplateRenderer interface {
	Render(template string, params map[string]string) (string, error)
}

TemplateRenderer renders templates with parameters

Jump to

Keyboard shortcuts

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