v0.88.0: app-email SMTP relay (in-process shim + per-app injection)

In-process go-smtp shim (Shape 1): apps → shim → hub → Resend, Resend key stays
hub-side. From-header allowlist (reject 5xx pre-hub), single-shot raw-MIME forward,
status→SMTP mapping. Global + per-app toggles gate compose-time env injection from
.felhom.yml smtp_mapping. Hungarian UI on settings + app config pages.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-29 08:45:04 +02:00
parent 7cddb885e0
commit 0e20eb19c1
22 changed files with 1619 additions and 64 deletions
+4
View File
@@ -101,6 +101,9 @@ type AppConfig struct {
DeployedAt string `yaml:"deployed_at" json:"deployed_at"`
Env map[string]string `yaml:"env" json:"env"`
LockedFields []string `yaml:"locked_fields" json:"locked_fields"`
// EmailEnabled is the per-app app-email toggle (default off). When on AND the global toggle is
// on AND the app has an smtp_mapping, the controller injects the relay SMTP env at compose time.
EmailEnabled bool `yaml:"email_enabled,omitempty" json:"email_enabled,omitempty"`
}
// DeployRequest contains the user-provided values from the deploy form.
@@ -702,6 +705,7 @@ func SaveAppConfig(stackDir string, cfg *AppConfig, encKey []byte, sensitiveVars
DeployedAt: cfg.DeployedAt,
Env: make(map[string]string, len(cfg.Env)),
LockedFields: cfg.LockedFields,
EmailEnabled: cfg.EmailEnabled,
}
sensitiveSet := make(map[string]bool, len(sensitiveVars))
for _, v := range sensitiveVars {