import os import logging from jinja2 import Environment, FileSystemLoader, select_autoescape from repositories.brief_repository import brief_repository logger = logging.getLogger(__name__) RESEND_API_KEY = os.getenv('RESEND_API_KEY') TEMPLATES_DIR = os.path.join(os.path.dirname(__file__), '..', 'templates', 'emails') # Plain Jinja2 (not flask.render_template) so this service has no # dependency on an active Flask request/app context — it must also run # from the n8n-triggered Flask route AND, in principle, from an RQ # worker process. Autoescaping is mandatory: brief content includes # scraped third-party trip names which must never be interpreted as # HTML in the rendered email. _jinja_env = Environment( loader=FileSystemLoader(TEMPLATES_DIR), autoescape=select_autoescape(['html']) ) def send_weekly_brief(tenant_id): """ Renders the weekly intelligence brief as branded HTML and sends it via Resend to the tenant admin email. Data flow: tenant_id → brief_repository.get_weekly_data() (price_history, new products, battlecard updates for the past 7 days) → brief.html Jinja2 template rendered → Resend API → digest_logs record created (sent or failed) """ data = brief_repository.get_weekly_data(tenant_id) admin_email = data.get('admin_email') if not admin_email: logger.error(f'No admin_email on file for tenant {tenant_id} — skipping weekly brief') return template = _jinja_env.get_template('brief.html') html = template.render(**data) try: # Imported lazily so this module is importable without the # `resend` package configured in test environments. import resend resend.api_key = RESEND_API_KEY resend.Emails.send({ 'from': 'Bettersight ', 'to': admin_email, 'subject': f"Bettersight Weekly Brief — Week of {data['week_of']}", 'html': html, }) brief_repository.log_digest(tenant_id, 'weekly', recipient_email=admin_email, status='sent') except Exception as e: # A failed email send is a side-effect failure — it must not # raise into the n8n workflow that triggered this run. logger.error(f'Weekly brief send failed for tenant {tenant_id}: {str(e)}') brief_repository.log_digest(tenant_id, 'weekly', recipient_email=admin_email, status='failed')