"""Email service for sending verification and notification emails.""" import asyncio from typing import Optional, Dict, Any from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart import aiosmtplib import logging import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent.parent)) from core.config import settings logger = logging.getLogger(__name__) class EmailService: """Service for sending emails.""" @staticmethod async def send_email( to_email: str, subject: str, html_content: str, text_content: Optional[str] = None ) -> bool: """ Send an email asynchronously. Args: to_email: Recipient email address subject: Email subject html_content: HTML email content text_content: Plain text content (optional) Returns: True if sent successfully, False otherwise """ try: # Create message message = MIMEMultipart("alternative") message["From"] = settings.SMTP_FROM_EMAIL message["To"] = to_email message["Subject"] = subject # Add text and HTML parts if text_content: text_part = MIMEText(text_content, "plain") message.attach(text_part) html_part = MIMEText(html_content, "html") message.attach(html_part) # Send email if settings.ENVIRONMENT == "development": # In development, just log the email logger.info(f"Email would be sent to {to_email}: {subject}") logger.debug(f"Email content: {html_content}") return True # Send via SMTP async with aiosmtplib.SMTP( hostname=settings.SMTP_HOST, port=settings.SMTP_PORT, use_tls=settings.SMTP_TLS, start_tls=settings.SMTP_SSL ) as smtp: if settings.SMTP_USER and settings.SMTP_PASSWORD: await smtp.login(settings.SMTP_USER, settings.SMTP_PASSWORD) await smtp.send_message(message) logger.info(f"Email sent successfully to {to_email}") return True except Exception as e: logger.error(f"Failed to send email to {to_email}: {e}") return False @staticmethod def send_verification_email(email: str, token: str) -> None: """ Send email verification link. Args: email: User email address token: Verification token """ # Create verification URL if settings.ENVIRONMENT == "development": base_url = "http://localhost:3000" else: base_url = "https://youtube-summarizer.com" # Replace with actual domain verification_url = f"{base_url}/auth/verify-email?token={token}" # Email content subject = f"Verify your email - {settings.APP_NAME}" html_content = f"""

{settings.APP_NAME}

Verify Your Email Address

Thank you for signing up! Please click the button below to verify your email address:

Verify Email

Or copy and paste this link in your browser:

{verification_url}

This link will expire in {settings.EMAIL_VERIFICATION_EXPIRE_HOURS} hours.

""" text_content = f""" Verify Your Email Address Thank you for signing up for {settings.APP_NAME}! Please verify your email address by clicking the link below: {verification_url} This link will expire in {settings.EMAIL_VERIFICATION_EXPIRE_HOURS} hours. If you didn't create an account, you can safely ignore this email. """ # Send email asynchronously in background (for production, use a proper task queue) try: loop = asyncio.get_running_loop() loop.create_task( EmailService.send_email(email, subject, html_content, text_content) ) except RuntimeError: # No event loop running, log the email content instead (development mode) logger.info(f"Email verification would be sent to {email} with token: {token}") logger.info(f"Verification URL: {settings.FRONTEND_URL}/verify-email?token={token}") @staticmethod def send_password_reset_email(email: str, token: str) -> None: """ Send password reset email. Args: email: User email address token: Password reset token """ # Create reset URL if settings.ENVIRONMENT == "development": base_url = "http://localhost:3000" else: base_url = "https://youtube-summarizer.com" # Replace with actual domain reset_url = f"{base_url}/auth/reset-password?token={token}" # Email content subject = f"Password Reset - {settings.APP_NAME}" html_content = f"""

Password Reset Request

Reset Your Password

We received a request to reset your password for your {settings.APP_NAME} account.

Reset Password

Or copy and paste this link in your browser:

{reset_url}

Security Note: This link will expire in {settings.PASSWORD_RESET_EXPIRE_MINUTES} minutes. After resetting your password, all existing sessions will be logged out for security.
""" text_content = f""" Password Reset Request We received a request to reset your password for your {settings.APP_NAME} account. Reset your password by clicking the link below: {reset_url} This link will expire in {settings.PASSWORD_RESET_EXPIRE_MINUTES} minutes. Security Note: After resetting your password, all existing sessions will be logged out for security. If you didn't request a password reset, please ignore this email or contact support if you have concerns. """ # Send email asynchronously in background (for production, use a proper task queue) try: loop = asyncio.get_running_loop() loop.create_task( EmailService.send_email(email, subject, html_content, text_content) ) except RuntimeError: # No event loop running, log the email content instead (development mode) logger.info(f"Password reset email would be sent to {email} with token: {token}") logger.info(f"Reset URL: {settings.FRONTEND_URL}/reset-password?token={token}") @staticmethod def send_welcome_email(email: str, username: Optional[str] = None) -> None: """ Send welcome email to new user. Args: email: User email address username: Optional username """ subject = f"Welcome to {settings.APP_NAME}!" display_name = username or email.split('@')[0] html_content = f"""

Welcome to {settings.APP_NAME}!

Hi {display_name}!

Your account has been successfully created and verified. You can now enjoy all the features of {settings.APP_NAME}:

✅ Summarize YouTube videos with AI
✅ Save and organize your summaries
✅ Export summaries in multiple formats
✅ Access your summary history
Go to Dashboard

Need help getting started? Check out our Help Center or reply to this email.

""" text_content = f""" Welcome to {settings.APP_NAME}! Hi {display_name}! Your account has been successfully created and verified. You can now enjoy all the features: ✅ Summarize YouTube videos with AI ✅ Save and organize your summaries ✅ Export summaries in multiple formats ✅ Access your summary history Get started: http://localhost:3000/dashboard Need help? Visit http://localhost:3000/help or reply to this email. Happy summarizing! """ # Send email asynchronously asyncio.create_task( EmailService.send_email(email, subject, html_content, text_content) )