Files
Kevin_Ramirez bdd089954b
Some checks failed
Build Producción & Push a Harbor / test (push) Failing after 3s
Build Producción & Push a Harbor / build (push) Has been skipped
Aduanasoft/plantillas-proyectos/pipeline/head There was a failure building this commit
feat: plantilla base workspace SaaS
2026-07-21 13:59:00 -05:00

119 lines
4.3 KiB
Python

"""
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"""
<html>
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333;">
<div style="max-width: 600px; margin: 0 auto; padding: 20px;">
<h2 style="color: #2563eb; border-bottom: 2px solid #2563eb; padding-bottom: 10px;">
Reporte de Facturas
</h2>
<p>{body_text}</p>
<p style="margin-top: 20px;">
El reporte se encuentra adjunto en formato CSV.
</p>
<hr style="margin: 30px 0; border: none; border-top: 1px solid #e5e7eb;">
<p style="font-size: 12px; color: #6b7280;">
Este es un correo generado automáticamente. Por favor no responder.
</p>
<p style="font-size: 12px; color: #6b7280;">
Generado el {datetime.now().strftime('%d/%m/%Y a las %H:%M')}
</p>
</div>
</body>
</html>
"""
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