From 917a7b8f2f81590024f6d39c05f4b505a4cb7b50 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 14 Jun 2026 15:11:53 +0000 Subject: [PATCH] Make email template placeholders configurable via environment variables --- Dockerfile | 6 ++++++ scraibe/email_sender.py | 34 +++++++++++++++++++++++++++++++--- scraibe/tasks.py | 21 +++++++++------------ 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5f3a98f..e7f3574 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,6 +36,12 @@ ENV CELERY_BROKER_URL=redis://localhost:6379/0 ENV CELERY_RESULT_BACKEND=redis://localhost:6379/0 ENV SCRAIBE_UPLOAD_DIR=/tmp/scraibe_uploads +# Email and template configuration +ENV EMAIL_CONTACT_ADDRESS=support@example.com +ENV EMAIL_CSS_PATH= +ENV SCRAIBE_TEMPLATES_DIR=/app/src/misc +ENV SCRABIE_VERSION=0.1.1.dev + # Copy and install Python dependencies COPY requirements.txt /app/src/requirements.txt RUN pip install --no-cache-dir -r requirements.txt diff --git a/scraibe/email_sender.py b/scraibe/email_sender.py index c58fe18..9a2061b 100644 --- a/scraibe/email_sender.py +++ b/scraibe/email_sender.py @@ -4,6 +4,7 @@ Email sender module for ScrAIbe. Sends transcription outputs (TXT, JSON, etc.) via SMTP. All credentials are configured via environment variables. Supports both plain text and HTML email bodies. +Template placeholders are primarily filled via environment variables. """ import os @@ -13,7 +14,7 @@ from email import encoders from email.mime.base import MIMEBase from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText -from typing import List, Optional +from typing import List, Optional, Dict, Any logger = logging.getLogger("scraibe.email_sender") @@ -52,7 +53,31 @@ def get_email_config(): } -def load_template(template_name: str, **kwargs) -> str: +def build_template_context(**runtime_kwargs: Any) -> Dict[str, Any]: + """ + Build a context dict for templates from: + - environment variables (base, customizable) + - runtime-provided values (override env if present) + + Environment variables: + - EMAIL_CONTACT_ADDRESS: value for {contact_email} + - EMAIL_CSS_PATH: value for {css_path} + + Runtime kwargs are merged on top (e.g. queue_position, exception). + """ + ctx: Dict[str, Any] = { + "contact_email": os.getenv("EMAIL_CONTACT_ADDRESS", "support@example.com"), + "css_path": os.getenv("EMAIL_CSS_PATH", ""), + } + + # Runtime values override env if provided + if runtime_kwargs: + ctx.update(runtime_kwargs) + + return ctx + + +def load_template(template_name: str, **runtime_kwargs: Any) -> str: """ Load an HTML email template from misc/ and render placeholders. @@ -70,9 +95,12 @@ def load_template(template_name: str, **kwargs) -> str: with open(path, "r", encoding="utf-8") as f: template = f.read() + # Build context from env + runtime + ctx = build_template_context(**runtime_kwargs) + # Replace {placeholder} style variables safely try: - return template.format(**kwargs) + return template.format(**ctx) except KeyError as e: raise EmailError(f"Missing template variable: {e}") diff --git a/scraibe/tasks.py b/scraibe/tasks.py index a441ecc..c4c8f98 100644 --- a/scraibe/tasks.py +++ b/scraibe/tasks.py @@ -15,9 +15,6 @@ from .email_sender import send_email, EmailError, load_template logger = logging.getLogger("scraibe.tasks") -# Contact email used in templates; can be overridden via env -CONTACT_EMAIL = os.getenv("EMAIL_CONTACT_ADDRESS", "support@example.com") - def get_queue_position(task_id: str) -> int: """ @@ -42,6 +39,7 @@ def get_queue_position(task_id: str) -> int: def send_initial_email(to: str, queue_pos: int): """ Send initial confirmation email with queue position using HTML template. + Static placeholders (contact_email, css_path) come from env via load_template. """ subject = "ScrAIbe: Your transcription request has been received" @@ -61,17 +59,16 @@ def send_initial_email(to: str, queue_pos: int): "You will receive an email with your transcript (and summary, if requested) " "once processing is complete.\n\n" "If you have any questions, contact us at " - f"{CONTACT_EMAIL}.\n\n" + f"{os.getenv('EMAIL_CONTACT_ADDRESS', 'support@example.com')}.\n\n" "This is an automated message from ScrAIbe.\n" ) - # Build HTML using template + # Build HTML using template; only dynamic value is queue_position html = None try: html = load_template( "upload_notification_template.html", queue_position=str(queue_pos) if queue_pos > 0 else "the queue", - contact_email=CONTACT_EMAIL, ) except EmailError as e: logger.warning("Failed to render upload notification template: %s", e) @@ -92,6 +89,7 @@ def send_success_email( ): """ Send final email with transcript and attachments using HTML template. + Static placeholders (contact_email, css_path) come from env via load_template. """ subject = "ScrAIbe: Your transcript is ready" @@ -114,16 +112,15 @@ def send_success_email( "\n" "Job ID: " + str(task_id) + "\n\n" "If you have any questions, contact us at " - f"{CONTACT_EMAIL}.\n\n" + f"{os.getenv('EMAIL_CONTACT_ADDRESS', 'support@example.com')}.\n\n" "This is an automated message from ScrAIbe.\n" ) - # Build HTML using template + # Build HTML using template; no dynamic placeholders needed html = None try: html = load_template( "success_template.html", - contact_email=CONTACT_EMAIL, ) except EmailError as e: logger.warning("Failed to render success template: %s", e) @@ -144,6 +141,7 @@ def send_success_email( def send_error_email(to: str, error_message: str, task_id: str): """ Send error notification email using HTML template. + Static placeholders (contact_email, css_path) come from env via load_template. """ subject = "ScrAIbe: Error with your transcription request" @@ -155,17 +153,16 @@ def send_error_email(to: str, error_message: str, task_id: str): "Job ID: " + str(task_id) + "\n\n" "Please contact your administrator if the problem persists.\n\n" "If you have any questions, contact us at " - f"{CONTACT_EMAIL}.\n\n" + f"{os.getenv('EMAIL_CONTACT_ADDRESS', 'support@example.com')}.\n\n" "This is an automated message from ScrAIbe.\n" ) - # Build HTML using template + # Build HTML using template; only dynamic placeholder is exception html = None try: html = load_template( "error_notification_template.html", exception=str(error_message), - contact_email=CONTACT_EMAIL, ) except EmailError as e: logger.warning("Failed to render error template: %s", e)