Documentation
¶
Overview ¶
Package smtp is the admin-configured mail server layer of the notification substrate: the stored connection settings, the admin API's write/read shapes with their validation, and the store that persists them with the password encrypted at rest.
It knows nothing about queues, preferences, or rendering. The send path (internal/notification/notifysend) takes a Settings value per call, so an admin change applies to the next send without a restart.
Index ¶
Constants ¶
const ( // TLSModeStartTLS negotiates STARTTLS on a plaintext connection (port 587). TLSModeStartTLS = "starttls" // TLSModeImplicit opens a TLS connection directly (port 465). TLSModeImplicit = "implicit" // TLSModeNone sends in plaintext. Only for closed-network relays. TLSModeNone = "none" )
SMTP TLS modes.
const PlaintextAuthWarning = "TLS is disabled (tls_mode: none) while SMTP credentials are configured; " +
"the username and password are sent in cleartext. Use starttls or implicit unless the relay is on a closed network."
PlaintextAuthWarning is reported when SMTP credentials are configured alongside TLSModeNone: go-mail then authenticates over an unencrypted connection, putting the username and password on the wire in the clear.
const SettingsSection = "smtp"
SettingsSection is the platform_settings section key for SMTP.
Variables ¶
var ( // ErrNotFound is returned by the store when SMTP has never been configured. ErrNotFound = errors.New("notification: smtp settings not found") // ErrNotConfigured is returned by delivery actions when SMTP is absent, // disabled, or missing a host; the caller should surface it as a // configuration conflict, not a delivery failure. ErrNotConfigured = errors.New("notification: smtp is disabled or not configured") )
Sentinel errors returned by this package.
Functions ¶
This section is empty.
Types ¶
type PostgresStore ¶
type PostgresStore struct {
// contains filtered or unexported fields
}
PostgresStore implements SettingsStore backed by the platform_settings table. Secrets inside a section value are encrypted with the injected StringEncryptor before they reach the database.
func NewPostgresStore ¶
func NewPostgresStore(db *sql.DB, enc StringEncryptor) *PostgresStore
NewPostgresStore creates a PostgreSQL-backed settings store. The encryptor may be nil-safe (encryption disabled) but must not be nil.
type Settings ¶
type Settings struct {
Enabled bool `json:"enabled"`
Host string `json:"host"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
// From is the sender address, e.g. "platform@example.com".
From string `json:"from"`
// FromName is the optional display name for the From address.
FromName string `json:"from_name"`
// TLSMode is one of the TLSMode* constants.
TLSMode string `json:"tls_mode"`
// UpdatedBy and UpdatedAt describe the last admin write.
UpdatedBy string `json:"updated_by,omitempty"`
UpdatedAt time.Time `json:"updated_at"`
}
Settings is the admin-configured mail server connection. The password is encrypted at rest and never returned by the admin API.
func (*Settings) View ¶
func (s *Settings) View() SettingsView
View maps stored settings to the password-free read shape.
type SettingsInput ¶
type SettingsInput struct {
Enabled bool `json:"enabled" example:"true"`
Host string `json:"host" example:"smtp.example.com"`
Port int `json:"port" example:"587"`
Username string `json:"username,omitempty" example:"mailer@example.com"`
Password string `json:"password,omitempty" example:"app-password"`
From string `json:"from" example:"platform@example.com"`
FromName string `json:"from_name,omitempty" example:"Data Platform"`
TLSMode string `json:"tls_mode,omitempty" example:"starttls"`
}
SettingsInput is the write shape for the admin SMTP configuration. An empty password keeps the currently stored one.
func (*SettingsInput) Settings ¶
func (in *SettingsInput) Settings() Settings
Settings maps the validated input to store settings.
func (*SettingsInput) Validate ¶
func (in *SettingsInput) Validate() string
Validate normalizes defaults in place and returns a non-empty message when the input is invalid. Omitted fields take defaults (port 587, STARTTLS) so a minimal `{"enabled": false}` disable call works.
type SettingsStore ¶
type SettingsStore interface {
// Get returns the stored SMTP settings with the password decrypted,
// or ErrNotFound when SMTP has never been configured.
Get(ctx context.Context) (*Settings, error)
// Set upserts the SMTP settings, encrypting the password at rest.
// An empty incoming password preserves the previously stored one so the
// admin UI can stay write-only without re-sending the secret.
Set(ctx context.Context, s Settings, author string) error
}
SettingsStore persists the admin's SMTP configuration. It is the SMTP section of the platform_settings table; another global setting would add its own contract over the same table rather than widen this one.
type SettingsView ¶
type SettingsView struct {
Enabled bool `json:"enabled" example:"true"`
Host string `json:"host" example:"smtp.example.com"`
Port int `json:"port" example:"587"`
Username string `json:"username" example:"mailer@example.com"`
PasswordSet bool `json:"password_set" example:"true"`
From string `json:"from" example:"platform@example.com"`
FromName string `json:"from_name" example:"Data Platform"`
TLSMode string `json:"tls_mode" example:"starttls"`
UpdatedBy string `json:"updated_by,omitempty" example:"admin@example.com"`
UpdatedAt time.Time `json:"updated_at"`
// Warnings describes accepted-but-hazardous combinations in the stored
// configuration. They never block a save; they exist so the operator sees
// the hazard at the surface where the setting was chosen.
Warnings []string `json:"warnings,omitempty"`
}
SettingsView is the read shape for the admin SMTP configuration. The password is write-only: the view reports only whether one is stored.
func UnconfiguredView ¶
func UnconfiguredView() SettingsView
UnconfiguredView is the read shape served before SMTP has ever been configured: disabled, with the transport defaults prefilled.
type StringEncryptor ¶
type StringEncryptor interface {
Encrypt(plaintext string) (string, error)
Decrypt(ciphertext string) (string, error)
}
StringEncryptor encrypts and decrypts a single string secret. Satisfied by fieldcrypt.RestFieldEncryptor; a nil-safe passthrough is acceptable when encryption is disabled.
type TestEmailRequest ¶
type TestEmailRequest struct {
To string `json:"to" example:"admin@example.com"`
}
TestEmailRequest is the body for the admin send-test-email action.
func (*TestEmailRequest) Validate ¶
func (r *TestEmailRequest) Validate() string
Validate returns a non-empty message when the recipient is invalid.