"""
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