""" Email service for sending transactional emails. Uses SMTP for sending emails. In production, consider using: - SendGrid, Mailgun, AWS SES, or other email service providers """ import aiosmtplib from email.message import EmailMessage from typing import Optional import os from config import settings async def send_password_reset_email(email: str, reset_token: str, frontend_url: str = "http://localhost:3002") -> bool: """ Send a password reset email to the user. Args: email: User's email address reset_token: Password reset token frontend_url: Frontend URL for constructing the reset link Returns: True if email was sent successfully, False otherwise """ if not settings.emails_enabled: print(f"Email sending disabled. Would send reset email to: {email}") print(f"Reset token: {reset_token}") return True if not settings.email_username or not settings.email_password: print("Email credentials not configured. Skipping email send.") print(f"RESET TOKEN FOR {email}: {reset_token}") return True # Return True to not break the flow in demo mode try: # Create the email message message = EmailMessage() message["From"] = f"{settings.email_from_name} <{settings.email_from or settings.email_username}>" message["To"] = email message["Subject"] = "Reset Your TaskFlow Password" # Construct the reset link reset_link = f"{frontend_url}/reset-password?token={reset_token}" # HTML email body html_body = f""" Reset Your Password

Reset Your Password

Hello,

We received a request to reset the password for your TaskFlow account. Click the button below to choose a new password:

Reset Password

Or copy and paste this link into your browser:

{reset_link}

Important: This link will expire in 1 hour for your security. If you didn't request this password reset, please ignore this email.
""" # Plain text alternative text_body = f""" Reset Your TaskFlow Password Hello, We received a request to reset the password for your TaskFlow account. Click the link below to choose a new password: {reset_link} If you're having trouble clicking the link, copy and paste the URL into your web browser. Important: This link will expire in 1 hour for your security. If you didn't request this password reset, please ignore this email. © 2026 TaskFlow. All rights reserved. """ message.set_content(text_body) message.add_alternative(html_body, subtype="html") # Send the email await aiosmtplib.send( message, hostname=settings.email_host, port=settings.email_port, username=settings.email_username, password=settings.email_password, start_tls=True, ) print(f"Password reset email sent successfully to: {email}") return True except Exception as e: print(f"Failed to send password reset email to {email}: {str(e)}") print(f"RESET TOKEN FOR {email}: {reset_token}") # In demo mode, we don't want to fail the entire flow if email sending fails return True async def send_email( to_email: str, subject: str, html_body: str, text_body: Optional[str] = None ) -> bool: """ Generic email sending function. Args: to_email: Recipient email address subject: Email subject html_body: HTML email body text_body: Optional plain text alternative Returns: True if email was sent successfully, False otherwise """ if not settings.emails_enabled: print(f"Email sending disabled. Would send email to: {to_email}") return True if not settings.email_username or not settings.email_password: print("Email credentials not configured. Skipping email send.") return True try: message = EmailMessage() message["From"] = f"{settings.email_from_name} <{settings.email_from or settings.email_username}>" message["To"] = to_email message["Subject"] = subject message.set_content(text_body or html_body) message.add_alternative(html_body, subtype="html") await aiosmtplib.send( message, hostname=settings.email_host, port=settings.email_port, username=settings.email_username, password=settings.email_password, start_tls=True, ) print(f"Email sent successfully to: {to_email}") return True except Exception as e: print(f"Failed to send email to {to_email}: {str(e)}") return False