from flask import current_app from flask_mail import Mail, Message import os def send_verification_email(to_email: str, token: str) -> None: verify_url = f"{current_app.config['FRONTEND_URL']}/auth/verify?token={token}" html_body = f'Click here to verify your account.' msg = Message( subject="Verify your account", 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 # Skip sending emails during e2e tests to avoid cluttering inboxes and logs Mail(current_app).send(msg) print(f"[EMAIL to {to_email}] Verification: {verify_url}") except Exception: print(f"Failed to send email to {to_email}. Verification link: {verify_url}") def send_reset_password_email(to_email: str, token: str) -> None: reset_url = f"{current_app.config['FRONTEND_URL']}/auth/reset-password?token={token}" html_body = f'Click here to reset your password.' msg = Message( subject="Reset your password", 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 # Skip sending emails during e2e tests to avoid cluttering inboxes and logs Mail(current_app).send(msg) print(f"[EMAIL to {to_email}] Reset password: {reset_url}") except Exception: print(f"Failed to send email to {to_email}. Reset link: {reset_url}") def send_pin_setup_email(to_email: str, code: str) -> None: html_body = f"""

Set up your Parent PIN

To set your Parent PIN, enter the following code in the app:

{code}

This code is valid for 10 minutes.

If you did not request this, you can ignore this email.


Reward App
""" msg = Message( subject="Set up your 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 # Skip sending emails during e2e tests to avoid cluttering inboxes and logs 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}" # Group items by child from collections import defaultdict 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""" {item['entity_name']} {entity_label} View Approve Deny """ child_sections += f"""

{child_name}

{rows}
""" html_body = f"""

Reward App — Daily Summary

You have pending items that need your attention:

{child_sections}
Reward App • Unsubscribe from daily digest
""" msg = Message( subject='Reward App — 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}")