import httpx from app.core.settings import settings class IntegrationProviderError(RuntimeError): """Erro de transporte ou configuracao em providers externos.""" class BrevoEmailProvider: provider_name = "brevo_email" def __init__(self) -> None: self.base_url = str(settings.brevo_base_url or "https://api.brevo.com/v3").rstrip("/") self.api_key = str(settings.brevo_api_key or "").strip() self.sender_email = str(settings.brevo_sender_email or "").strip() self.sender_name = str(settings.brevo_sender_name or "Orquestrador").strip() or "Orquestrador" self.timeout_seconds = max(1, int(settings.brevo_request_timeout_seconds or 10)) def is_configured(self) -> bool: return bool(self.api_key and self.sender_email) async def send_email( self, *, to_email: str, to_name: str | None, subject: str, body: str, tags: list[str] | None = None, ) -> dict: if not self.is_configured(): raise IntegrationProviderError( "Brevo nao configurado. Defina BREVO_API_KEY e BREVO_SENDER_EMAIL para enviar emails." ) payload = { "sender": { "email": self.sender_email, "name": self.sender_name, }, "to": [ { "email": str(to_email or "").strip(), **({"name": str(to_name).strip()} if str(to_name or "").strip() else {}), } ], "subject": str(subject or "").strip(), "textContent": str(body or "").strip(), } if tags: payload["tags"] = [str(tag).strip() for tag in tags if str(tag).strip()] headers = { "accept": "application/json", "content-type": "application/json", "api-key": self.api_key, } try: async with httpx.AsyncClient(timeout=self.timeout_seconds) as client: response = await client.post( f"{self.base_url}/smtp/email", headers=headers, json=payload, ) except httpx.HTTPError as exc: raise IntegrationProviderError(f"Falha ao enviar email via Brevo: {exc}") from exc if response.status_code >= 400: raise IntegrationProviderError( f"Brevo retornou erro {response.status_code}: {response.text[:300]}" ) try: data = response.json() except ValueError: data = {} return { "provider": self.provider_name, "message_id": data.get("messageId"), "response": data, }