""" Email Service - SendGrid integration for verification and password reset emails. """ import os import secrets from datetime import datetime, timedelta from typing import Optional import httpx SENDGRID_API_KEY = os.getenv("SENDGRID_API_KEY", "") EMAIL_FROM = os.getenv("EMAIL_FROM", "noreply@elmeg.xyz") FRONTEND_URL = os.getenv("FRONTEND_URL", "https://elmeg.runfoo.run") async def send_email(to: str, subject: str, html_content: str) -> bool: """Send email via SendGrid API""" if not SENDGRID_API_KEY: print(f"[EMAIL DEV MODE] To: {to}, Subject: {subject}") print(f"[EMAIL DEV MODE] Content: {html_content[:200]}...") return True async with httpx.AsyncClient() as client: response = await client.post( "https://api.sendgrid.com/v3/mail/send", headers={ "Authorization": f"Bearer {SENDGRID_API_KEY}", "Content-Type": "application/json" }, json={ "personalizations": [{"to": [{"email": to}]}], "from": {"email": EMAIL_FROM, "name": "Elmeg"}, "subject": subject, "content": [{"type": "text/html", "value": html_content}] } ) return response.status_code in (200, 202) def generate_token() -> str: """Generate a secure random token""" return secrets.token_urlsafe(32) async def send_verification_email(email: str, token: str) -> bool: """Send email verification link""" verify_url = f"{FRONTEND_URL}/verify-email?token={token}" html = f"""

Welcome to Elmeg!

Please verify your email address by clicking the button below:

Verify Email

Or copy this link: {verify_url}

This link expires in 48 hours.

""" return await send_email(email, "Verify your Elmeg account", html) async def send_password_reset_email(email: str, token: str) -> bool: """Send password reset link""" reset_url = f"{FRONTEND_URL}/reset-password?token={token}" html = f"""

Password Reset

You requested a password reset. Click below to set a new password:

Reset Password

Or copy this link: {reset_url}

This link expires in 1 hour. If you didn't request this, ignore this email.

""" return await send_email(email, "Reset your Elmeg password", html) # Token expiration helpers def get_verification_expiry() -> datetime: """48 hour expiry for email verification""" return datetime.utcnow() + timedelta(hours=48) def get_reset_expiry() -> datetime: """1 hour expiry for password reset""" return datetime.utcnow() + timedelta(hours=1)