from collections import defaultdict from flask import current_app from flask_mail import Mail, Message import os # --------------------------------------------------------------------------- # Shared email template # --------------------------------------------------------------------------- def _build_email_html(content_html: str, frontend_url: str) -> str: """Wrap content in the standard Chorly branded email shell.""" logo_url = f"{frontend_url}/images/full_logo.png" return f"""
|
Welcome to Chorly! Click the button below to confirm your email address and activate your account.
{_primary_button('Verify My Account', verify_url)}
If you didn't create a Chorly account, you can safely ignore this email.
Or copy this link into your browser: {verify_url}
We received a request to reset your Chorly password. Click the button below to choose a new one. This link expires in 10 minutes.
{_primary_button('Reset My Password', reset_url)}
If you didn't request a password reset, you can safely ignore this email —
your password will not change.
Or copy this link into your browser: {reset_url}
To set your Parent PIN, enter the following code in the app. It is valid for 10 minutes.
If you did not request this, you can safely ignore this email.
""" html_body = _build_email_html(content, frontend_url) msg = Message( subject="Set up your Chorly Parent PIN", recipients=[to_email], html=html_body, sender=current_app.config.get('MAIL_DEFAULT_SENDER', 'no-reply@reward-app.local') ) try: if os.environ.get('DB_ENV') == 'e2e': return Mail(current_app).send(msg) print(f"[EMAIL to {to_email}] Parent PIN setup code: {code}") except Exception: print(f"Failed to send email to {to_email}. Parent PIN setup code: {code}") def send_digest_email(to_email: str, items: list, unsubscribe_token: str) -> None: """ Send the nightly digest email listing pending chore/reward items. Each item in `items` is a dict with keys: child_name, entity_name, entity_type, view_url, approve_url, deny_url Items are grouped by child_name in the email. """ frontend_url = current_app.config.get('FRONTEND_URL', 'https://localhost:5173') unsubscribe_url = f"{frontend_url}/api/digest-unsubscribe/{unsubscribe_token}" by_child: dict = defaultdict(list) for item in items: by_child[item['child_name']].append(item) child_sections = '' for child_name, child_items in by_child.items(): rows = '' for item in child_items: entity_label = 'Chore' if item['entity_type'] == 'chore' else 'Reward' rows += f"""You have pending items that need your attention:
{child_sections} """ html_body = _build_email_html(content, frontend_url) msg = Message( subject='Chorly \u2014 Daily Summary', recipients=[to_email], html=html_body, sender=current_app.config.get('MAIL_DEFAULT_SENDER', 'no-reply@reward-app.local'), ) try: if os.environ.get('DB_ENV') == 'e2e': return Mail(current_app).send(msg) print(f"[EMAIL to {to_email}] Daily digest sent ({len(items)} items)") except Exception: print(f"Failed to send digest email to {to_email}")