Documentation
¶
Overview ¶
Package email sends transactional mail via the Resend HTTP API.
Rivolt previously had no direct email path — Kratos was the only component that talked to Resend, and it did so via SMTP. The signup-request approval flow needs Rivolt itself to send a one-off "you're in, here's your invite code" mail, so this package wraps Resend's REST endpoint with a tiny client.
HTTP rather than SMTP keeps the dependency surface flat (no STARTTLS dance, no net/smtp) and reuses the same Resend account/sender domain that Kratos already authenticates against.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNotConfigured = errors.New("email: client not configured")
ErrNotConfigured is returned by Send when called on a nil Client so admin handlers can branch cleanly ("email not configured — copy the code manually") without a separate has-email check at every site.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client posts to https://api.resend.com/emails.
func New ¶
New returns a Client, or nil when APIKey/From are empty so the caller can wire the dependency optionally without a separate "disabled" type.
func (*Client) FromAddress ¶ added in v0.18.25
FromAddress returns the bare email parsed out of the configured `Name <addr>` From string (e.g. "Rivolt <support@rivolt.dev>" → "support@rivolt.dev"). Empty when the client is nil or when the From has no angle-bracketed address. Used by admin notifications so the same env var that gates the verified sender also targets the admin's inbox — no second env var to keep in sync.
type Config ¶
Config carries the construction parameters. From must be a verified sender on the Resend account (e.g. "Rivolt <hello@rivolt.dev>").
type Counter ¶ added in v0.18.71
type Counter interface {
IncEmailSend(provider, status string)
}
Counter is the metric-recording surface the Resend client uses without taking a hard dependency on internal/metrics (avoids a package-level import cycle: metrics imports nothing application, application imports metrics from main, email is a leaf). Implementations must be safe for concurrent use.
type Message ¶
type Message struct {
To string
Subject string
Text string // plain-text body; rendered as-is
HTML string // optional HTML alternative; nil-coalesced to "" if absent
// Headers are extra message headers passed through Resend's
// `headers` object (List-Unsubscribe, List-Unsubscribe-Post). Names
// and values containing CR or LF are dropped so a value can never
// inject another header.
Headers map[string]string
// IdempotencyKey, when set, is sent as Resend's Idempotency-Key
// header so a retried send of the same message is not delivered
// twice.
IdempotencyKey string
}
Message is the shape Resend's /emails endpoint accepts. Only the fields the signup-approval template needs are exposed.