Make email template placeholders configurable via environment variables
This commit is contained in:
@@ -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
@@ -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
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user