118 lines
4.2 KiB
Python
118 lines
4.2 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 - Sistema Anexo76
|
|
</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
|
|
attachment = MIMEBase('text', 'csv')
|
|
attachment.set_payload(csv_content.encode('utf-8'))
|
|
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
|