Documentation
¶
Index ¶
- Constants
- func HTTPStatus(err error) int
- type CFMail
- func (c *CFMail) From() string
- func (c *CFMail) GetDependencies() []string
- func (c *CFMail) GetInitOrderStage() cf.Stage
- func (c *CFMail) Health(ctx context.Context) error
- func (c *CFMail) Init(ctx context.Context, fw *cf.CaerusFramework) error
- func (c *CFMail) Metrics() []cf_observability.Metric
- func (c *CFMail) Name() string
- func (c *CFMail) OnConfigReload(source string, cfg any)
- func (c *CFMail) Provider() string
- func (c *CFMail) RegisterConfigSources(conf any) error
- func (c *CFMail) ResendClient() *resend.Client
- func (c *CFMail) ResendProfiles() []string
- func (c *CFMail) SESClient() *sesv2.Client
- func (c *CFMail) Send(ctx context.Context, m Mail) (string, error)
- func (c *CFMail) SendWithProfile(ctx context.Context, profile string, m Mail) (string, error)
- func (c *CFMail) Shutdown(ctx context.Context) error
- type Mail
- type MailConfig
- type Option
- func WithConfig(cfg MailConfig) Option
- func WithConfigSource(name, path string, opts ...SourceOption) Option
- func WithFromAddress(from string) Option
- func WithHTTPClient(hc *http.Client) Option
- func WithLogger(logger *slog.Logger) Option
- func WithName(name string) Option
- func WithProvider(provider string) Option
- func WithResendAPIKey(apiKey string) Option
- func WithResendBaseURL(baseURL string) Option
- func WithResendDefaultProfile(name string) Option
- func WithResendProfiles(profiles map[string]ResendProfile) Option
- func WithSESCredentials(accessKeyID, secretAccessKey string) Option
- func WithSESEndpoint(endpoint string) Option
- func WithSESRegion(region string) Option
- func WithTimeout(d time.Duration) Option
- func WithUnisenderGoAPIKey(apiKey string) Option
- func WithUnisenderGoBaseURL(baseURL string) Option
- type ResendProfile
- type ResendSettings
- type SESSettings
- type SendError
- type SourceOption
- type UnisenderGoSettings
Constants ¶
const ( // ProviderResend is the Resend transactional API (resend.com). ProviderResend = "resend" // ProviderSES is Amazon SES v2 SendEmail (transactional). ProviderSES = "ses" // ProviderUnisenderGo is Unisender Go transactional email/send // (goapi.unisender.ru). It is not the Unisender.com campaign API. ProviderUnisenderGo = "unisender_go" )
const ( // ComponentName is the framework component name for the mail component. ComponentName = "mail" // ComponentStage is the stage data-layer components initialize in. ComponentStage = cf.Stage("data") )
Variables ¶
This section is empty.
Functions ¶
func HTTPStatus ¶
HTTPStatus returns the provider HTTP status from err when err is (or wraps) a SendError. It returns 0 for nil, validation errors, network failures, and SDK errors that did not go through Send.
Types ¶
type CFMail ¶
type CFMail struct {
// contains filtered or unexported fields
}
CFMail is the caerus-framework-mail component. Apps hold this pointer and call Send per use. The active provider is a config setting, not a second component type.
func (*CFMail) From ¶
From returns the configured soft-default sender. When Resend default_profile is active, that is the profile's from_address.
func (*CFMail) GetDependencies ¶
GetDependencies implements cf.Dependencies.
func (*CFMail) GetInitOrderStage ¶
GetInitOrderStage implements cf.CaerusComponent.
func (*CFMail) Health ¶
Health implements cf.HealthProvider. Providers expose no liveness endpoint; health reflects that a sender is initialized.
func (*CFMail) Metrics ¶
func (c *CFMail) Metrics() []cf_observability.Metric
Metrics implements cf_observability.MetricsProvider.
func (*CFMail) OnConfigReload ¶
OnConfigReload implements cf.ConfigReloader. On failure the previous sender is kept (last-good).
func (*CFMail) RegisterConfigSources ¶
RegisterConfigSources implements cf.ConfigSourceRegistrar.
func (*CFMail) ResendClient ¶
ResendClient returns the live Resend SDK client for the default sender, or nil when the active provider is not resend (or before Init / after Shutdown). With named profiles this is the legacy api_key client, or the default_profile client when that setting is set — not a profile picked via SendWithProfile.
func (*CFMail) ResendProfiles ¶ added in v0.0.2
ResendProfiles returns the sorted names of configured Resend profiles (empty when the provider is not resend or no profiles are set).
func (*CFMail) SESClient ¶
SESClient returns the live SES v2 client, or nil when the active provider is not ses (or before Init / after Shutdown).
func (*CFMail) Send ¶
Send sends m through the configured provider and returns the provider message id (Resend id, SES MessageId, Unisender Go job_id).
From: from_address / WithFromAddress is a soft default when Mail.From is empty. When Resend default_profile is set, that profile's from_address is the soft default instead. If both are empty, or the resolved From or any To address does not parse (`net/mail.ParseAddress`), Send fails. HTML and Text may both be set; at least one must be non-empty.
For a named Resend API key / From pair, use SendWithProfile.
If the first HTTP status is 429 or 5xx, Send waits (Retry-After, capped at 1s) and tries once more while ctx is live. 4xx other than 429 and network errors are not retried.
func (*CFMail) SendWithProfile ¶ added in v0.0.2
SendWithProfile sends m with a named Resend profile (resend.profiles[name]). Soft-default From is that profile's from_address; Mail.From still overrides. SES and Unisender Go have no profiles — use Send and set Mail.From instead.
type Mail ¶
type Mail struct {
// From overrides from_address when non-empty. Empty (or whitespace)
// uses the configured soft default. The resolved value must parse as
// an RFC 5322 address (`net/mail.ParseAddress`).
From string
To []string
Subject string
HTML string
Text string
ReplyTo string
// Tags are provider metadata (name → value). Empty names are skipped.
// Resend and SES send name/value pairs. Unisender Go uses the names as
// its string tags (max 4) and the pairs as global_metadata (max 10).
Tags map[string]string
// IdempotencyKey is forwarded when the provider supports it (Resend
// Idempotency-Key header; Unisender Go idempotence_key). SES v2 SendEmail
// has no matching field; it is ignored there.
IdempotencyKey string
}
Mail is the Caerus send DTO (SES-simple shape). Apps pass this to Send without importing a provider SDK. Attachments, Cc/Bcc, headers, and scheduled send stay on the provider escape hatches (ResendClient / SESClient) for callers that opt into an SDK.
type MailConfig ¶
type MailConfig struct {
// Provider selects the sender: resend, ses, or unisender_go.
Provider string `json:"provider" yaml:"provider" env:"PROVIDER"`
// FromAddress is the soft-default sender. Send uses it when Mail.From is empty.
FromAddress string `json:"from_address" yaml:"from_address" env:"FROM_ADDRESS"`
// TimeoutSec bounds each provider HTTP call (default 10s).
TimeoutSec float64 `json:"timeout_sec,omitempty" yaml:"timeout_sec,omitempty" env:"TIMEOUT_SEC"`
Resend ResendSettings `json:"resend,omitempty" yaml:"resend,omitempty" env:"-"`
SES SESSettings `json:"ses,omitempty" yaml:"ses,omitempty" env:"-"`
UnisenderGo UnisenderGoSettings `json:"unisender_go,omitempty" yaml:"unisender_go,omitempty" env:"-"`
// Flat env aliases (nested JSON/YAML still wins when both are set after
// merge: env overlay fills these, applyConfig copies them into the nested
// structs when the nested field is still empty).
ResendAPIKey string `json:"-" yaml:"-" env:"RESEND_API_KEY" secret:"redact"`
ResendBaseURL string `json:"-" yaml:"-" env:"RESEND_BASE_URL"`
SESRegion string `json:"-" yaml:"-" env:"SES_REGION"`
SESAccessKeyID string `json:"-" yaml:"-" env:"SES_ACCESS_KEY_ID"`
SESSecretAccessKey string `json:"-" yaml:"-" env:"SES_SECRET_ACCESS_KEY" secret:"redact"`
SESEndpoint string `json:"-" yaml:"-" env:"SES_ENDPOINT"`
UnisenderGoAPIKey string `json:"-" yaml:"-" env:"UNISENDER_GO_API_KEY" secret:"redact"`
UnisenderGoBaseURL string `json:"-" yaml:"-" env:"UNISENDER_GO_BASE_URL"`
UnisenderGoSkipUnsub *bool `json:"-" yaml:"-" env:"UNISENDER_GO_SKIP_UNSUBSCRIBE"`
}
MailConfig is the file/env-drivable configuration. Shared settings sit at the top; each provider has a nested object. The configuration overlay does not walk nested structs for env, so the flat MAIL_* aliases below exist for local/`go run` (same pattern as valkey-state RATE_LIMIT_*).
type Option ¶
type Option func(*options)
Option configures the mail component at construction time.
func WithConfig ¶
func WithConfig(cfg MailConfig) Option
WithConfig sets a static configuration snapshot. Non-zero fields of cfg override the values set by the convenience options. Prefer WithConfigSource when using caerus-framework-configuration with hot-reload.
func WithConfigSource ¶
func WithConfigSource(name, path string, opts ...SourceOption) Option
WithConfigSource binds this component to a named configuration source and registers that source with the configuration component (via the framework's ConfigSourceRegistrar pass during argv absorption).
cf_mail.New(cf_mail.WithConfigSource("mail", "config/mail.json"))
A path of "" registers an env-only (fileless) source when the EnvPrefix is non-empty. The path CLI override stays --<source-name> (ParseFlags). Declares a dependency on "configuration".
func WithFromAddress ¶
WithFromAddress sets the soft-default sender. Send uses it when Mail.From is empty. A non-empty Mail.From overrides this call only.
func WithHTTPClient ¶
WithHTTPClient overrides the HTTP client used by every provider. Useful for tests (a stub RoundTripper). The component does not close a client it did not create.
func WithLogger ¶
WithLogger overrides the logger used for component diagnostics. By default the component logs through the framework logs component.
func WithName ¶
WithName sets a custom component name, allowing multiple mail instances in the same process. The default name is "mail" (ComponentName).
func WithProvider ¶
WithProvider selects the sender (resend, ses, unisender_go). Required unless the bound config file sets provider.
func WithResendAPIKey ¶
WithResendAPIKey sets the Resend API key (tests, embedded use).
func WithResendBaseURL ¶
WithResendBaseURL overrides the Resend API endpoint.
func WithResendDefaultProfile ¶ added in v0.0.2
WithResendDefaultProfile names the profiles entry Send uses by default.
func WithResendProfiles ¶ added in v0.0.2
func WithResendProfiles(profiles map[string]ResendProfile) Option
WithResendProfiles sets named Resend senders (api_key + from per name). Prefer the config file's resend.profiles in production.
func WithSESCredentials ¶
WithSESCredentials sets static AWS keys. Leave unset to use the default credential chain (IRSA / shared config).
func WithSESEndpoint ¶
WithSESEndpoint overrides the SES v2 endpoint (LocalStack / tests).
func WithSESRegion ¶
WithSESRegion sets the AWS region for SES v2.
func WithTimeout ¶
WithTimeout sets the per-send HTTP timeout (default 10s).
func WithUnisenderGoAPIKey ¶
WithUnisenderGoAPIKey sets the Unisender Go API key.
func WithUnisenderGoBaseURL ¶
WithUnisenderGoBaseURL overrides the Unisender Go transactional base URL.
type ResendProfile ¶ added in v0.0.2
type ResendProfile struct {
APIKey string `json:"api_key" yaml:"api_key" secret:"redact"`
FromAddress string `json:"from_address" yaml:"from_address"`
// BaseURL overrides ResendSettings.BaseURL for this profile only.
BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty"`
}
ResendProfile is one named Resend API key + From pair.
type ResendSettings ¶
type ResendSettings struct {
APIKey string `json:"api_key" yaml:"api_key" env:"-" secret:"redact"`
BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty" env:"-"`
// DefaultProfile names the profiles entry Send uses when set. Empty
// keeps Send on the legacy api_key + top-level from_address.
DefaultProfile string `json:"default_profile,omitempty" yaml:"default_profile,omitempty" env:"-"`
// Profiles are named Resend senders (one API key + From per name).
Profiles map[string]ResendProfile `json:"profiles,omitempty" yaml:"profiles,omitempty" env:"-"`
}
ResendSettings is the nested Resend blob.
Two shapes are supported (they may be combined):
- Legacy single key — api_key + top-level from_address. Send uses that pair. Flat MAIL_RESEND_API_KEY still fills api_key.
- Named profiles — profiles map (each api_key + from_address). Use SendWithProfile to pick one. Optional default_profile makes Send use that profile when set.
Profiles exist because Resend API keys are often bound to one domain.
type SESSettings ¶
type SESSettings struct {
Region string `json:"region" yaml:"region" env:"-"`
AccessKeyID string `json:"access_key_id,omitempty" yaml:"access_key_id,omitempty" env:"-"`
SecretAccessKey string `json:"secret_access_key,omitempty" yaml:"secret_access_key,omitempty" env:"-" secret:"redact"`
Endpoint string `json:"endpoint,omitempty" yaml:"endpoint,omitempty" env:"-"`
}
SESSettings is the nested Amazon SES v2 blob.
Credentials: set both AccessKeyID and SecretAccessKey in the file (K8s Secret mount). Leave both empty to use the default AWS chain (IRSA in cluster, shared config on a laptop). Setting only one is an Init error.
type SendError ¶
type SendError struct {
// contains filtered or unexported fields
}
SendError is returned by Send when the provider HTTP call failed. HTTPStatus is filled from the component transport (the same source as mail_emails_failed_total).
Status 0 means a transport/network failure or an unknown status.
func (*SendError) HTTPStatus ¶
HTTPStatus is the provider API status for this send, or 0 if the request never got an HTTP response.
type SourceOption ¶
type SourceOption func(*sourceOptions)
SourceOption configures the self-registered configuration source created by WithConfigSource.
func WithSourceEnvPrefix ¶
func WithSourceEnvPrefix(prefix string) SourceOption
WithSourceEnvPrefix sets the environment overlay prefix for the source (default: the uppercase source name with "-" replaced by "_", plus "_"). An empty prefix disables env overlay.
func WithSourceFormat ¶
func WithSourceFormat(f cf_configuration.Format) SourceOption
WithSourceFormat forces the file format instead of inferring it from the path extension (".yaml"/".yml" → YAML; anything else JSON).
type UnisenderGoSettings ¶
type UnisenderGoSettings struct {
APIKey string `json:"api_key" yaml:"api_key" env:"-" secret:"redact"`
BaseURL string `json:"base_url,omitempty" yaml:"base_url,omitempty" env:"-"`
SkipUnsubscribe *bool `json:"skip_unsubscribe,omitempty" yaml:"skip_unsubscribe,omitempty" env:"-"`
}
UnisenderGoSettings is the nested Unisender Go transactional blob. Default BaseURL is https://goapi.unisender.ru/en/transactional/api/v1 (override for go1/go2 datacenters). This is not api.unisender.com.