from __future__ import annotations from datetime import datetime from email.message import EmailMessage import smtplib from app.extensions import db from app.models.invoice import Invoice, MailDelivery from app.services.pdf_service import PdfService from app.services.settings_service import SettingsService class MailService: def __init__(self, company_id=None): self.company_id = company_id def _smtp_config(self): security_mode = (SettingsService.get_effective('mail.security_mode', '', company_id=self.company_id) or '').strip().lower() if security_mode not in {'tls', 'ssl', 'none'}: security_mode = 'tls' if str(SettingsService.get_effective('mail.tls', 'true', company_id=self.company_id)).lower() == 'true' else 'none' return { 'server': (SettingsService.get_effective('mail.server', '', company_id=self.company_id) or '').strip(), 'port': int(SettingsService.get_effective('mail.port', '587', company_id=self.company_id) or 587), 'username': (SettingsService.get_effective('mail.username', '', company_id=self.company_id) or '').strip(), 'password': (SettingsService.get_effective_secret('mail.password', '', company_id=self.company_id) or '').strip(), 'sender': (SettingsService.get_effective('mail.sender', '', company_id=self.company_id) or '').strip(), 'security_mode': security_mode, } def send_invoice(self, invoice: Invoice, recipient: str, subject: str | None = None, body: str | None = None): subject = subject or f'Faktura {invoice.invoice_number}' body = body or f'W załączeniu faktura {invoice.invoice_number}.' delivery = MailDelivery(invoice_id=invoice.id, recipient=recipient, subject=subject, status='queued') db.session.add(delivery) db.session.flush() pdf_bytes, path = PdfService().render_invoice_pdf(invoice) try: self.send_mail( recipient, subject, body, [(path.name, 'application/pdf', pdf_bytes)] ) delivery.status = 'sent' delivery.sent_at = datetime.utcnow() except Exception as exc: delivery.status = 'error' delivery.error_message = str(exc) db.session.commit() return delivery def send_mail(self, recipient: str, subject: str, body: str, attachments=None): cfg = self._smtp_config() attachments = attachments or [] if not cfg['server']: raise RuntimeError('SMTP server not configured') sender = cfg['sender'] or cfg['username'] if not sender: raise RuntimeError('SMTP sender not configured') message = EmailMessage() message['Subject'] = subject message['From'] = sender message['To'] = recipient message.set_content(body) for filename, mime, data in attachments: maintype, subtype = mime.split('/', 1) message.add_attachment(data, maintype=maintype, subtype=subtype, filename=filename) if cfg['security_mode'] == 'ssl': smtp = smtplib.SMTP_SSL(cfg['server'], cfg['port']) else: smtp = smtplib.SMTP(cfg['server'], cfg['port']) with smtp: smtp.ehlo() if cfg['security_mode'] == 'tls': smtp.starttls() smtp.ehlo() if cfg['username']: smtp.login(cfg['username'], cfg['password']) smtp.send_message(message) return {'status': 'sent'} def send_test_mail(self, recipient: str): return self.send_mail( recipient, 'KSeF Manager - test SMTP', 'To jest testowa wiadomość z aplikacji KSeF Manager.' ) def retry_delivery(self, delivery_id): delivery = db.session.get(MailDelivery, delivery_id) return self.send_invoice(delivery.invoice, delivery.recipient, delivery.subject)