diff --git a/main.py b/main.py index 031cb58..a4cb9db 100644 --- a/main.py +++ b/main.py @@ -57,8 +57,7 @@ from functools import wraps from starlette.middleware.sessions import SessionMiddleware from uvicorn.middleware.proxy_headers import ProxyHeadersMiddleware from authlib.integrations.starlette_client import OAuth -import sendgrid -from sendgrid.helpers.mail import Mail + AGENT_ID = "osvauco-opax" PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT", "propane-will-491900-m5") @@ -305,7 +304,7 @@ async def vm_ssh_key(instance: str = "osvauco-dev-vm"): @app.get("/notify/channels") async def get_notify_channels(): return {"channels": [ - {"type": "email", "configured": bool(os.getenv("SENDGRID_API_KEY")), "target": os.getenv("NOTIFY_EMAIL_TO")}, + {"type": "email", "configured": bool(os.getenv("GMAIL_DEFAULT_SENDER")), "target": os.getenv("NOTIFY_EMAIL_TO")}, {"type": "sms", "configured": bool(os.getenv("TWILIO_ACCOUNT_SID")), "target": os.getenv("TWILIO_FROM_NUMBER")}, {"type": "webhook", "configured": bool(os.getenv("NOTIFY_WEBHOOK_URL")), "url": os.getenv("NOTIFY_WEBHOOK_URL")}, ]} @@ -473,20 +472,49 @@ class NotificationService: return {"status": "error", "detail": str(e)} async def send_email(self, req) -> dict: - api_key = os.environ.get("SENDGRID_API_KEY") + import base64 + import os + from email.mime.text import MIMEText + from email.mime.multipart import MIMEMultipart + from google.auth import default as google_auth_default + from googleapiclient.discovery import build + to_email = req.to or ALERT_EMAIL - if not api_key: - return {"status": "not_configured", "detail": "SENDGRID_API_KEY mangler"} if not to_email: - return {"status": "not_configured", "detail": "Ingen mottaker-e-post"} + return {"status": "skipped", "reason": "no recipient"} + + allowed_senders_str = os.getenv("GMAIL_ALLOWED_SENDERS", "") + allowed = [s.strip() for s in allowed_senders_str.split(",") if s.strip()] + sender = os.getenv("GMAIL_DEFAULT_SENDER") + + if not sender or not allowed: + return {"status": "not_configured", "reason": "GMAIL_DEFAULT_SENDER or GMAIL_ALLOWED_SENDERS not set"} + + if sender not in allowed: + return {"status": "error", "reason": f"Default sender {sender} is not in the allowed list"} + meta = self._event_meta(req.event) subject = req.subject or f"{meta['emoji']} CostGuard: {meta['label']} — {datetime.date.today()}" html_content = req.body_html if req.body_html else await self._build_digest_html(req.payload) + try: - message = Mail(from_email="costguard@osvauco.no", to_emails=to_email, subject=subject, html_content=html_content) - sg = sendgrid.SendGridAPIClient(api_key) - response = sg.send(message) - return {"status": "ok", "message_id": response.headers.get("X-Message-Id", ""), "to": to_email, "event": req.event} + credentials, _ = google_auth_default(scopes=["https://www.googleapis.com/auth/gmail.send"]) + credentials = credentials.with_subject(sender) + + service = build("gmail", "v1", credentials=credentials) + + message = MIMEMultipart("alternative") + message["to"] = to_email + message["from"] = sender + message["subject"] = subject + message.attach(MIMEText(html_content, "html")) + + raw = base64.urlsafe_b64encode(message.as_bytes()).decode() + result = service.users().messages().send( + userId="me", body={"raw": raw} + ).execute() + + return {"status": "ok", "message_id": result.get("id", ""), "to": to_email, "event": req.event} except Exception as e: return {"status": "error", "detail": str(e)}