Make email template placeholders configurable via environment variables
Mirror and run GitLab CI / build (push) Has been cancelled
Ruff / ruff (push) Has been cancelled

This commit is contained in:
admin
2026-06-14 15:11:53 +00:00
parent 85cdd9216a
commit 917a7b8f2f
3 changed files with 46 additions and 15 deletions
+6
View File
@@ -36,6 +36,12 @@ ENV CELERY_BROKER_URL=redis://localhost:6379/0
ENV CELERY_RESULT_BACKEND=redis://localhost:6379/0 ENV CELERY_RESULT_BACKEND=redis://localhost:6379/0
ENV SCRAIBE_UPLOAD_DIR=/tmp/scraibe_uploads 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 and install Python dependencies
COPY requirements.txt /app/src/requirements.txt COPY requirements.txt /app/src/requirements.txt
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
+31 -3
View File
@@ -4,6 +4,7 @@ Email sender module for ScrAIbe.
Sends transcription outputs (TXT, JSON, etc.) via SMTP. Sends transcription outputs (TXT, JSON, etc.) via SMTP.
All credentials are configured via environment variables. All credentials are configured via environment variables.
Supports both plain text and HTML email bodies. Supports both plain text and HTML email bodies.
Template placeholders are primarily filled via environment variables.
""" """
import os import os
@@ -13,7 +14,7 @@ from email import encoders
from email.mime.base import MIMEBase from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText from email.mime.text import MIMEText
from typing import List, Optional from typing import List, Optional, Dict, Any
logger = logging.getLogger("scraibe.email_sender") 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. 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: with open(path, "r", encoding="utf-8") as f:
template = f.read() template = f.read()
# Build context from env + runtime
ctx = build_template_context(**runtime_kwargs)
# Replace {placeholder} style variables safely # Replace {placeholder} style variables safely
try: try:
return template.format(**kwargs) return template.format(**ctx)
except KeyError as e: except KeyError as e:
raise EmailError(f"Missing template variable: {e}") raise EmailError(f"Missing template variable: {e}")
+9 -12
View File
@@ -15,9 +15,6 @@ from .email_sender import send_email, EmailError, load_template
logger = logging.getLogger("scraibe.tasks") 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: 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): def send_initial_email(to: str, queue_pos: int):
""" """
Send initial confirmation email with queue position using HTML template. 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" 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) " "You will receive an email with your transcript (and summary, if requested) "
"once processing is complete.\n\n" "once processing is complete.\n\n"
"If you have any questions, contact us at " "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" "This is an automated message from ScrAIbe.\n"
) )
# Build HTML using template # Build HTML using template; only dynamic value is queue_position
html = None html = None
try: try:
html = load_template( html = load_template(
"upload_notification_template.html", "upload_notification_template.html",
queue_position=str(queue_pos) if queue_pos > 0 else "the queue", queue_position=str(queue_pos) if queue_pos > 0 else "the queue",
contact_email=CONTACT_EMAIL,
) )
except EmailError as e: except EmailError as e:
logger.warning("Failed to render upload notification template: %s", 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. 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" subject = "ScrAIbe: Your transcript is ready"
@@ -114,16 +112,15 @@ def send_success_email(
"\n" "\n"
"Job ID: " + str(task_id) + "\n\n" "Job ID: " + str(task_id) + "\n\n"
"If you have any questions, contact us at " "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" "This is an automated message from ScrAIbe.\n"
) )
# Build HTML using template # Build HTML using template; no dynamic placeholders needed
html = None html = None
try: try:
html = load_template( html = load_template(
"success_template.html", "success_template.html",
contact_email=CONTACT_EMAIL,
) )
except EmailError as e: except EmailError as e:
logger.warning("Failed to render success template: %s", 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): def send_error_email(to: str, error_message: str, task_id: str):
""" """
Send error notification email using HTML template. 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" 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" "Job ID: " + str(task_id) + "\n\n"
"Please contact your administrator if the problem persists.\n\n" "Please contact your administrator if the problem persists.\n\n"
"If you have any questions, contact us at " "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" "This is an automated message from ScrAIbe.\n"
) )
# Build HTML using template # Build HTML using template; only dynamic placeholder is exception
html = None html = None
try: try:
html = load_template( html = load_template(
"error_notification_template.html", "error_notification_template.html",
exception=str(error_message), exception=str(error_message),
contact_email=CONTACT_EMAIL,
) )
except EmailError as e: except EmailError as e:
logger.warning("Failed to render error template: %s", e) logger.warning("Failed to render error template: %s", e)