"""Background email sending tasks.""" from datetime import datetime from typing import Optional from celery import shared_task from src.core.celery_app import celery_app from src.core.logging_config import get_logger, set_correlation_id from src.core.config import settings logger = get_logger(__name__) @celery_app.task( bind=True, max_retries=3, default_retry_delay=300, # 5 minutes time_limit=60, rate_limit="100/m", ) def send_email( self, to_email: str, subject: str, body_html: Optional[str] = None, body_text: Optional[str] = None, from_email: Optional[str] = None, reply_to: Optional[str] = None, attachments: Optional[list] = None, template_name: Optional[str] = None, template_context: Optional[dict] = None, ): """Send email asynchronously. Args: to_email: Recipient email address subject: Email subject body_html: HTML body content body_text: Plain text body content from_email: Sender email address reply_to: Reply-to address attachments: List of attachment files template_name: Email template name template_context: Template context variables """ correlation_id = set_correlation_id() logger.info( "Sending email", extra={ "to_email": to_email, "subject": subject, "template": template_name, "correlation_id": correlation_id, }, ) try: # Get email configuration smtp_host = getattr(settings, "smtp_host", "localhost") smtp_port = getattr(settings, "smtp_port", 587) smtp_user = getattr(settings, "smtp_user", None) smtp_password = getattr(settings, "smtp_password", None) from_addr = from_email or getattr( settings, "default_from_email", "noreply@mockupaws.com" ) # Import here to avoid import issues if email not configured import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders # Create message msg = MIMEMultipart("alternative") msg["Subject"] = subject msg["From"] = from_addr msg["To"] = to_email if reply_to: msg["Reply-To"] = reply_to # Add body if body_text: msg.attach(MIMEText(body_text, "plain")) if body_html: msg.attach(MIMEText(body_html, "html")) # Send email with smtplib.SMTP(smtp_host, smtp_port) as server: if smtp_user and smtp_password: server.starttls() server.login(smtp_user, smtp_password) server.send_message(msg) logger.info( "Email sent successfully", extra={"to_email": to_email, "subject": subject}, ) return {"status": "sent", "to": to_email, "subject": subject} except Exception as exc: logger.exception(f"Failed to send email to {to_email}") raise self.retry(exc=exc, countdown=300) @celery_app.task( bind=True, max_retries=3, default_retry_delay=60, ) def send_password_reset_email( self, to_email: str, reset_token: str, reset_url: str, ): """Send password reset email. Args: to_email: User email address reset_token: Password reset token reset_url: Password reset URL """ correlation_id = set_correlation_id() subject = "Password Reset Request - mockupAWS" body_html = f"""

Password Reset Request

You have requested to reset your password for mockupAWS.

Click the link below to reset your password:

Reset Password

This link will expire in 1 hour.

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

""" body_text = f""" Password Reset Request You have requested to reset your password for mockupAWS. Click the link below to reset your password: {reset_url}?token={reset_token} This link will expire in 1 hour. If you did not request this, please ignore this email. """ return send_email.delay( to_email=to_email, subject=subject, body_html=body_html, body_text=body_text, ) @celery_app.task( bind=True, max_retries=3, default_retry_delay=60, ) def send_welcome_email( self, to_email: str, user_name: str, ): """Send welcome email to new user. Args: to_email: User email address user_name: User's full name """ correlation_id = set_correlation_id() subject = "Welcome to mockupAWS!" body_html = f"""

Welcome to mockupAWS!

Hi {user_name},

Thank you for joining mockupAWS. Your account has been successfully created.

You can now start creating cost simulation scenarios and generating reports.

If you have any questions, please don't hesitate to contact our support team.


Best regards,
The mockupAWS Team

""" body_text = f""" Welcome to mockupAWS! Hi {user_name}, Thank you for joining mockupAWS. Your account has been successfully created. You can now start creating cost simulation scenarios and generating reports. If you have any questions, please don't hesitate to contact our support team. Best regards, The mockupAWS Team """ return send_email.delay( to_email=to_email, subject=subject, body_html=body_html, body_text=body_text, ) @celery_app.task( bind=True, max_retries=3, default_retry_delay=60, ) def send_report_ready_email( self, to_email: str, report_name: str, download_url: str, ): """Send report ready notification email. Args: to_email: User email address report_name: Name of the report download_url: URL to download the report """ correlation_id = set_correlation_id() subject = f"Your Report is Ready - {report_name}" body_html = f"""

Your Report is Ready

Your report "{report_name}" has been generated successfully.

Click the link below to download your report:

Download Report

The report will be available for download for 30 days.

""" body_text = f""" Your Report is Ready Your report "{report_name}" has been generated successfully. Download your report: {download_url} The report will be available for download for 30 days. """ return send_email.delay( to_email=to_email, subject=subject, body_html=body_html, body_text=body_text, )