diff --git a/.github/workflows/deploy-prod.yaml b/.github/workflows/deploy-prod.yaml index 8004cac..3591be9 100644 --- a/.github/workflows/deploy-prod.yaml +++ b/.github/workflows/deploy-prod.yaml @@ -92,6 +92,13 @@ jobs: CSAS_CLIENT_ID: ${{ secrets.CSAS_CLIENT_ID }} CSAS_CLIENT_SECRET: ${{ secrets.CSAS_CLIENT_SECRET }} SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SMTP_HOST: ${{ secrets.SMTP_HOST }} + SMTP_PORT: ${{ secrets.SMTP_PORT }} + SMTP_USERNAME: ${{ secrets.SMTP_USERNAME }} + SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }} + SMTP_USE_TLS: ${{ secrets.SMTP_USE_TLS }} + SMTP_USE_SSL: ${{ secrets.SMTP_USE_SSL }} + SMTP_FROM: ${{ secrets.SMTP_FROM }} run: | helm upgrade --install myapp ./7project/charts/myapp-chart \ -n prod --create-namespace \ @@ -111,4 +118,11 @@ jobs: --set-string oauth.csas.clientId="$CSAS_CLIENT_ID" \ --set-string oauth.csas.clientSecret="$CSAS_CLIENT_SECRET" \ --set-string sentry_dsn="$SENTRY_DSN" \ - --set-string database.encryptionSecret="${{ secrets.PROD_DB_ENCRYPTION_KEY }}" \ No newline at end of file + --set-string database.encryptionSecret="${{ secrets.PROD_DB_ENCRYPTION_KEY }}" \ + --set-string smtp.host="$SMTP_HOST" \ + --set smtp.port="$SMTP_PORT" \ + --set-string smtp.username="$SMTP_USERNAME" \ + --set-string smtp.password="$SMTP_PASSWORD" \ + --set-string smtp.tls="$SMTP_USE_TLS" \ + --set-string smtp.ssl="$SMTP_USE_SSL" \ + --set-string smtp.from="$SMTP_FROM" \ No newline at end of file diff --git a/7project/backend/app/workers/celery_tasks.py b/7project/backend/app/workers/celery_tasks.py index 2c875d6..399f161 100644 --- a/7project/backend/app/workers/celery_tasks.py +++ b/7project/backend/app/workers/celery_tasks.py @@ -1,5 +1,8 @@ import logging import asyncio +import os +import smtplib +from email.message import EmailMessage from celery import shared_task @@ -84,8 +87,45 @@ def send_email(to: str, subject: str, body: str) -> None: logger.error("Email task missing fields. to=%r subject=%r body_len=%r", to, subject, len(body) if body else 0) return - # Placeholder for real email sending logic - logger.info("[Celery] Email sent | to=%s | subject=%s | body_len=%d", to, subject, len(body)) + host = os.getenv("SMTP_HOST") + if not host: + logger.error("SMTP_HOST is not configured; cannot send email") + return + + # Configuration + port = int(os.getenv("SMTP_PORT", "25")) + username = os.getenv("SMTP_USERNAME") + password = os.getenv("SMTP_PASSWORD") + use_tls = os.getenv("SMTP_USE_TLS", "0").lower() in {"1", "true", "yes"} + use_ssl = os.getenv("SMTP_USE_SSL", "0").lower() in {"1", "true", "yes"} + timeout = int(os.getenv("SMTP_TIMEOUT", "10")) + mail_from = os.getenv("SMTP_FROM") or username or "noreply@localhost" + + # Build message + msg = EmailMessage() + msg["To"] = to + msg["From"] = mail_from + msg["Subject"] = subject + msg.set_content(body) + + try: + if use_ssl: + with smtplib.SMTP_SSL(host=host, port=port, timeout=timeout) as smtp: + if username and password: + smtp.login(username, password) + smtp.send_message(msg) + else: + with smtplib.SMTP(host=host, port=port, timeout=timeout) as smtp: + # STARTTLS if requested + if use_tls: + smtp.starttls() + if username and password: + smtp.login(username, password) + smtp.send_message(msg) + logger.info("[Celery] Email sent | to=%s | subject=%s | body_len=%d", to, subject, len(body)) + except Exception: + logger.exception("Failed to send email via SMTP to=%s subject=%s host=%s port=%s tls=%s ssl=%s", to, subject, + host, port, use_tls, use_ssl) @shared_task(name="workers.load_transactions") diff --git a/7project/charts/myapp-chart/templates/prod.yaml b/7project/charts/myapp-chart/templates/prod.yaml index abb294a..01f76ef 100644 --- a/7project/charts/myapp-chart/templates/prod.yaml +++ b/7project/charts/myapp-chart/templates/prod.yaml @@ -19,3 +19,10 @@ stringData: RABBITMQ_USERNAME: {{ .Values.rabbitmq.username | quote }} SENTRY_DSN: {{ .Values.sentry_dsn | quote }} DB_ENCRYPTION_KEY: {{ required "Set .Values.database.encryptionSecret" .Values.database.encryptionSecret | quote }} + SMTP_HOST: {{ .Values.smtp.host | default "" | quote }} + SMTP_PORT: {{ .Values.smtp.port | default 587 | quote }} + SMTP_USERNAME: {{ .Values.smtp.username | default "" | quote }} + SMTP_PASSWORD: {{ .Values.smtp.password | default "" | quote }} + SMTP_USE_TLS: {{ .Values.smtp.tls | default false | quote }} + SMTP_USE_SSL: {{ .Values.smtp.ssl | default false | quote }} + SMTP_FROM: {{ .Values.smtp.from | default "" | quote }} diff --git a/7project/charts/myapp-chart/templates/worker-deployment.yaml b/7project/charts/myapp-chart/templates/worker-deployment.yaml index fbd5182..b6979c2 100644 --- a/7project/charts/myapp-chart/templates/worker-deployment.yaml +++ b/7project/charts/myapp-chart/templates/worker-deployment.yaml @@ -85,3 +85,38 @@ spec: secretKeyRef: name: prod key: DB_ENCRYPTION_KEY + - name: SMTP_HOST + valueFrom: + secretKeyRef: + name: prod + key: SMTP_HOST + - name: SMTP_PORT + valueFrom: + secretKeyRef: + name: prod + key: SMTP_PORT + - name: SMTP_USERNAME + valueFrom: + secretKeyRef: + name: prod + key: SMTP_USERNAME + - name: SMTP_PASSWORD + valueFrom: + secretKeyRef: + name: prod + key: SMTP_PASSWORD + - name: SMTP_USE_TLS + valueFrom: + secretKeyRef: + name: prod + key: SMTP_USE_TLS + - name: SMTP_USE_SSL + valueFrom: + secretKeyRef: + name: prod + key: SMTP_USE_SSL + - name: SMTP_FROM + valueFrom: + secretKeyRef: + name: prod + key: SMTP_FROM diff --git a/7project/charts/myapp-chart/values.yaml b/7project/charts/myapp-chart/values.yaml index b3bdb8c..cbffb51 100644 --- a/7project/charts/myapp-chart/values.yaml +++ b/7project/charts/myapp-chart/values.yaml @@ -42,6 +42,16 @@ cron: endpoint: "/_cron" concurrencyPolicy: "Forbid" +smtp: + host: + port: 587 + username: "" + password: "" + tls: false + ssl: false + from: "" + + service: port: 80