receipter-pro / backend /mailer_client.py
M8ion deploy
Deploy backend
45dc2a1
Raw History Blame Contribute Delete
1.71 kB
"""
The seam between the sending pipeline (backend/sending.py) and actual mail transport —
same pattern as backend/firestore_client.py for storage. Independent of LOCAL_MODE on
purpose: LOCAL_MODE governs storage (Firestore vs. the local shim), REAL_SEND_ENABLED
governs mail transport. You can want local storage with a real mailer (exactly the setup
used to verify a real send end-to-end without a GCP project) or, later, real storage with a
mock mailer (safe load-testing against prod-shaped data without actually emailing anyone).
Mailbox *verification* (backend/mailboxes.py's OTP round-trip) always uses the mock mailer
regardless of this flag — confirming a real round-trip would need reading the receiving
inbox back (IMAP), which is out of scope until the bounce-detection work in Phase 2 builds
that same scoped read capability. This module only governs the mailer used to actually send
a composed message once a connection is already marked verified.
"""
from __future__ import annotations
import os
from backend.mock_mailer import MockInbox, MockMailer
from backend.smtp_mailer import SMTPMailer
def real_send_enabled() -> bool:
return os.getenv("REAL_SEND_ENABLED", "false").lower() == "true"
def get_mailer(kind: str, credentials: dict):
if not real_send_enabled():
return MockMailer(credentials, MockInbox())
if kind == "smtp":
return SMTPMailer(credentials)
raise NotImplementedError(
f"Real sending for mailbox kind {kind!r} isn't wired up yet — no real Google Cloud "
f"OAuth app exists (see docs/engineering/env-config-reference.md). Set "
f"REAL_SEND_ENABLED=false, or connect this org's mailbox via SMTP instead."
)