push
This commit is contained in:
104
app/services/mail_service.py
Normal file
104
app/services/mail_service.py
Normal file
@@ -0,0 +1,104 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user