""" Email service for sending reports via SMTP. """ import aiosmtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.base import MIMEBase from email import encoders from typing import List import logging from datetime import datetime from core.config import settings logger = logging.getLogger(__name__) class EmailService: """Service for sending emails with attachments.""" @staticmethod async def send_report_email( recipient_email: str, subject: str, body_text: str, csv_content: str, filename: str ) -> bool: """ Send a report email with CSV attachment. Args: recipient_email: Email address of recipient subject: Email subject line body_text: Plain text email body csv_content: CSV file content as string filename: Name for the CSV attachment Returns: bool: True if email sent successfully, False otherwise """ try: # Create message msg = MIMEMultipart() msg['From'] = f"{settings.SMTP_FROM_NAME} <{settings.SMTP_USER}>" msg['To'] = recipient_email msg['Subject'] = subject # Email body html_body = f"""

Reporte de Facturas

{body_text}

El reporte se encuentra adjunto en formato CSV.


Este es un correo generado automáticamente. Por favor no responder.

Generado el {datetime.now().strftime('%d/%m/%Y a las %H:%M')}

""" msg.attach(MIMEText(html_body, 'html')) # CSV attachment with UTF-8 BOM for Excel compatibility attachment = MIMEBase('text', 'csv') csv_bytes = b'\xef\xbb\xbf' + csv_content.encode('utf-8') attachment.set_payload(csv_bytes) encoders.encode_base64(attachment) attachment.add_header( 'Content-Disposition', f'attachment; filename="{filename}"' ) msg.attach(attachment) # Create SSL context that ignores certificate errors import ssl context = ssl.create_default_context() context.check_hostname = False context.verify_mode = ssl.CERT_NONE # Send email if settings.SMTP_PORT == 465: # Port 465 uses implicit SSL async with aiosmtplib.SMTP( hostname=settings.SMTP_HOST, port=settings.SMTP_PORT, use_tls=True, # Implicit SSL tls_context=context ) as smtp: await smtp.login(settings.SMTP_USER, settings.SMTP_PASSWORD) await smtp.send_message(msg) else: # Port 587 uses STARTTLS async with aiosmtplib.SMTP( hostname=settings.SMTP_HOST, port=settings.SMTP_PORT, tls_context=context ) as smtp: await smtp.starttls(tls_context=context) await smtp.login(settings.SMTP_USER, settings.SMTP_PASSWORD) await smtp.send_message(msg) logger.info(f"Email sent successfully to {recipient_email}") return True except Exception as e: logger.error(f"Failed to send email to {recipient_email}: {str(e)}") return False