# Runtime and Components The diagram below focuses on the deployed `galaxy/mail` process and its runtime dependencies. ```mermaid flowchart LR subgraph Callers Auth["Auth / Session Service"] Notify["Notification Service"] Ops["Trusted operators"] end subgraph Mail["Mail Service process"] InternalHTTP["Trusted internal HTTP listener\n/api/v1/internal/*"] Consumer["Redis Stream command consumer"] Scheduler["Attempt scheduler"] Workers["Attempt worker pool"] Cleanup["Index cleanup worker"] Services["Application services"] Templates["Immutable template catalog"] Telemetry["Logs, traces, metrics"] end Redis["Redis\nstate + streams + indexes"] Provider["SMTP or stub provider"] Auth --> InternalHTTP Ops --> InternalHTTP Notify --> Redis InternalHTTP --> Services Consumer --> Services Scheduler --> Services Workers --> Services Cleanup --> Services Services --> Templates Services --> Redis Services --> Provider InternalHTTP --> Telemetry Consumer --> Telemetry Scheduler --> Telemetry Workers --> Telemetry ``` ## Listener `mail` exposes exactly one HTTP listener: | Listener | Default addr | Purpose | | --- | --- | --- | | Internal HTTP | `:8080` | Trusted intake, operator reads, and resend | Shared listener defaults: - read-header timeout: `2s` - read timeout: `10s` - idle timeout: `1m` Intentional omissions: - no public listener - no `/healthz` - no `/readyz` - no `/metrics` ## Startup Wiring `cmd/mail` loads config, constructs logging, and builds the runtime through `internal/app.NewRuntime`. The runtime wires: - Redis clients for state access and blocking stream consumption - filesystem-backed template catalog - provider adapter selected by `MAIL_SMTP_MODE` - acceptance, render, execution, operator-read, and resend services - internal HTTP server - command consumer - scheduler - attempt worker pool - cleanup worker Before startup completes, the process performs bounded `PING` checks for both Redis clients and validates the template catalog. Startup fails fast on invalid configuration or unavailable Redis. ## Background Components ### Command consumer - reads one plain `XREAD` stream - starts from stored offset or `0-0` - advances offset only after durable command acceptance or durable malformed command recording ### Scheduler - polls due work every `250ms` - recovers stale claims every `30s` - derives recovery deadline from `MAIL_SMTP_TIMEOUT + 30s` ### Attempt worker pool - processes only already claimed work items - concurrency is controlled by `MAIL_ATTEMPT_WORKER_CONCURRENCY` ### Cleanup worker - removes stale delivery-index members after primary delivery expiry - does not clean `mail:attempt_schedule` - does not clean malformed-command index entries ## Configuration Groups Required for all starts: - `MAIL_REDIS_ADDR` Core process config: - `MAIL_SHUTDOWN_TIMEOUT` - `MAIL_LOG_LEVEL` Internal HTTP config: - `MAIL_INTERNAL_HTTP_ADDR` - `MAIL_INTERNAL_HTTP_READ_HEADER_TIMEOUT` - `MAIL_INTERNAL_HTTP_READ_TIMEOUT` - `MAIL_INTERNAL_HTTP_IDLE_TIMEOUT` Redis connectivity: - `MAIL_REDIS_USERNAME` - `MAIL_REDIS_PASSWORD` - `MAIL_REDIS_DB` - `MAIL_REDIS_TLS_ENABLED` - `MAIL_REDIS_OPERATION_TIMEOUT` - `MAIL_REDIS_COMMAND_STREAM` - `MAIL_REDIS_ATTEMPT_SCHEDULE_KEY` - `MAIL_REDIS_DEAD_LETTER_PREFIX` SMTP provider: - `MAIL_SMTP_MODE` - `MAIL_SMTP_ADDR` - `MAIL_SMTP_USERNAME` - `MAIL_SMTP_PASSWORD` - `MAIL_SMTP_FROM_EMAIL` - `MAIL_SMTP_FROM_NAME` - `MAIL_SMTP_TIMEOUT` - `MAIL_SMTP_INSECURE_SKIP_VERIFY` Templates and workers: - `MAIL_TEMPLATE_DIR` - `MAIL_ATTEMPT_WORKER_CONCURRENCY` - `MAIL_STREAM_BLOCK_TIMEOUT` - `MAIL_OPERATOR_REQUEST_TIMEOUT` - `MAIL_IDEMPOTENCY_TTL` - `MAIL_DELIVERY_TTL` - `MAIL_ATTEMPT_TTL` Telemetry: - `OTEL_SERVICE_NAME` - `OTEL_TRACES_EXPORTER` - `OTEL_METRICS_EXPORTER` - `OTEL_EXPORTER_OTLP_PROTOCOL` - `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` - `OTEL_EXPORTER_OTLP_METRICS_PROTOCOL` - `MAIL_OTEL_STDOUT_TRACES_ENABLED` - `MAIL_OTEL_STDOUT_METRICS_ENABLED` ## Runtime Notes - `MAIL_REDIS_COMMAND_STREAM` is the only Redis key override that currently changes runtime behavior - `MAIL_SMTP_INSECURE_SKIP_VERIFY` is a local-development escape hatch for self-signed SMTP capture only and should remain disabled in production - attempt-schedule and dead-letter key overrides are parsed but not yet wired into Redis adapters - retention overrides are parsed but storage still uses the fixed `7d`, `30d`, and `90d` values - template catalog parsing is eager and immutable - auth deliveries in `MAIL_SMTP_MODE=stub` surface as `suppressed` - auth deliveries in `MAIL_SMTP_MODE=smtp` surface as `queued` and later move through normal attempt execution