From b3b5717e9e70cecc5eff46bb1a809cbb6e7a5f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Trkan?= Date: Tue, 11 Nov 2025 14:59:28 +0100 Subject: [PATCH 1/4] feat(infrastructure): add email sender --- .github/workflows/deploy-prod.yaml | 16 ++++++- 7project/backend/app/workers/celery_tasks.py | 44 ++++++++++++++++++- .../charts/myapp-chart/templates/prod.yaml | 7 +++ .../templates/worker-deployment.yaml | 35 +++++++++++++++ 7project/charts/myapp-chart/values.yaml | 10 +++++ 5 files changed, 109 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-prod.yaml b/.github/workflows/deploy-prod.yaml index 8004cac..be38115 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-string 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..2d03d9f 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 456 | 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..5079d16 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: 456 + username: "" + password: "" + tls: false + ssl: false + from: "" + + service: port: 80 From 9986cce8f9ab301f7948e0b85701a3d6c65a0fef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Trkan?= Date: Tue, 11 Nov 2025 15:03:36 +0100 Subject: [PATCH 2/4] Update 7project/charts/myapp-chart/values.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 7project/charts/myapp-chart/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/7project/charts/myapp-chart/values.yaml b/7project/charts/myapp-chart/values.yaml index 5079d16..cbffb51 100644 --- a/7project/charts/myapp-chart/values.yaml +++ b/7project/charts/myapp-chart/values.yaml @@ -44,7 +44,7 @@ cron: smtp: host: - port: 456 + port: 587 username: "" password: "" tls: false From 4cf0d2a9813fb642b3c2ee6c1e831ac13eea2144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Trkan?= Date: Tue, 11 Nov 2025 15:03:43 +0100 Subject: [PATCH 3/4] Update 7project/charts/myapp-chart/templates/prod.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- 7project/charts/myapp-chart/templates/prod.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/7project/charts/myapp-chart/templates/prod.yaml b/7project/charts/myapp-chart/templates/prod.yaml index 2d03d9f..01f76ef 100644 --- a/7project/charts/myapp-chart/templates/prod.yaml +++ b/7project/charts/myapp-chart/templates/prod.yaml @@ -20,7 +20,7 @@ stringData: 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 456 | 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 }} From 188cdf57274b4cd1cf59ad85ba1cbb7bf1a1368a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Trkan?= Date: Tue, 11 Nov 2025 15:03:53 +0100 Subject: [PATCH 4/4] Update .github/workflows/deploy-prod.yaml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/deploy-prod.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-prod.yaml b/.github/workflows/deploy-prod.yaml index be38115..3591be9 100644 --- a/.github/workflows/deploy-prod.yaml +++ b/.github/workflows/deploy-prod.yaml @@ -120,7 +120,7 @@ jobs: --set-string sentry_dsn="$SENTRY_DSN" \ --set-string database.encryptionSecret="${{ secrets.PROD_DB_ENCRYPTION_KEY }}" \ --set-string smtp.host="$SMTP_HOST" \ - --set-string smtp.port="$SMTP_PORT" \ + --set smtp.port="$SMTP_PORT" \ --set-string smtp.username="$SMTP_USERNAME" \ --set-string smtp.password="$SMTP_PASSWORD" \ --set-string smtp.tls="$SMTP_USE_TLS" \