Files
ksef_app/app/services/mail_service.py
Mateusz Gruszczyński 35571df778 push
2026-03-13 11:03:13 +01:00

104 lines
4.0 KiB
Python

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)