Skip to content

47 - SMTP Configuration

Storage

SMTP settings are columns on the single Settings row (__tablename__ = "settings") in database/settings_db.py; there is no separate SMTP database or email service module.

ColumnTypeNotes
smtp_serverString(255)Hostname
smtp_portIntegerRoute default is 587 when the form omits it
smtp_usernameString(255)
smtp_password_encryptedTextFernet ciphertext, never plaintext
smtp_use_tlsBooleanDefaults to True
smtp_from_emailString(255)
smtp_helo_hostnameString(255)Optional EHLO/HELO override

New password writes use _get_smtp_fernet(): PBKDF2-HMAC-SHA256, 100,000 iterations, keyed on the validated API_KEY_PEPPER with the salt from SMTP_KEY_SALT (env var, default smtp-tradeboard-salt). _decrypt_password() falls back to _legacy_smtp_fernet() (the raw pepper padded to 32 bytes, no KDF) for values written before that upgrade, and re-saving the settings migrates them forward. Decrypted passwords must never be returned by profile/admin APIs or logged.

Authenticated Routes

blueprints/auth.py exposes:

Method/pathPurpose
POST /auth/smtp-configUpdate settings from form fields; a blank password preserves the existing secret
POST /auth/test-smtpValidate recipient and send a test message
POST /auth/debug-smtpRun connection/auth diagnostics
GET /auth/profile-dataReturn non-secret config and password-present state

The React configuration UI is the SMTP tab in frontend/src/pages/Profile.tsx.

Delivery

utils/email_utils.py exposes send_test_email(), send_password_reset_email(), send_email(), and validate_smtp_settings(). Port 465 uses smtplib.SMTP_SSL from the start; any other port opens a plain SMTP connection and upgrades with starttls() when smtp_use_tls is set. smtp_helo_hostname is passed to ehlo(), falling back to smtp_server when it is blank. utils/email_debug.py performs staged diagnostics behind POST /auth/debug-smtp.

Security Rules

  • Require a valid app session and CSRF token for changes.
  • Preserve the existing password when the form leaves it blank.
  • Return password presence only, never ciphertext or plaintext.
  • Do not include credentials in SMTP errors or logs.
  • Prefer provider app passwords and TLS/SSL.
  • Treat debug output as authenticated operational data.

Key Files

FilePurpose
database/settings_db.pySettings and SMTP encryption
utils/email_utils.pyTest/reset/general delivery
utils/email_debug.pyConnection diagnostics
blueprints/auth.pyConfiguration routes
frontend/src/pages/Profile.tsxSMTP form