mirror of
https://github.com/idrainformatica/PecFlow.git
synced 2026-06-16 12:45:42 +02:00
Fix notification System
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
"""
|
||||
Email SMTP sender – invio notifiche via SMTP con TLS/SSL o STARTTLS.
|
||||
|
||||
Config non sensibile (config):
|
||||
{
|
||||
"smtp_host": "smtp.example.com",
|
||||
"smtp_port": 465,
|
||||
"smtp_use_tls": true, # SSL/TLS diretto (porta 465)
|
||||
"smtp_use_starttls": false, # STARTTLS (porta 587) – alternativo a use_tls
|
||||
"from_email": "noreply@example.com",
|
||||
"from_name": "PEChub Notifiche",
|
||||
"to_email": "destinatario@example.com"
|
||||
}
|
||||
|
||||
Config sensibile (config_enc → config_secret):
|
||||
{ "smtp_password": "..." }
|
||||
|
||||
Dipendenza: aiosmtplib (gia' in backend/pyproject.toml)
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
|
||||
import aiosmtplib
|
||||
|
||||
DEFAULT_TIMEOUT = 15.0
|
||||
|
||||
|
||||
class EmailSMTPError(Exception):
|
||||
"""Errore durante l'invio di un'email di notifica."""
|
||||
|
||||
def __init__(self, message: str, smtp_code: int | None = None):
|
||||
super().__init__(message)
|
||||
self.smtp_code = smtp_code
|
||||
|
||||
|
||||
async def send_email_notification(
|
||||
smtp_host: str,
|
||||
smtp_port: int,
|
||||
smtp_user: str,
|
||||
smtp_password: str,
|
||||
from_email: str,
|
||||
to_email: str,
|
||||
subject: str,
|
||||
body_text: str,
|
||||
body_html: str | None = None,
|
||||
from_name: str = "PEChub Notifiche",
|
||||
use_tls: bool = True,
|
||||
use_starttls: bool = False,
|
||||
timeout: float = DEFAULT_TIMEOUT,
|
||||
) -> None:
|
||||
"""
|
||||
Invia un'email di notifica via SMTP.
|
||||
|
||||
Args:
|
||||
smtp_host: host SMTP
|
||||
smtp_port: porta SMTP
|
||||
smtp_user: username autenticazione
|
||||
smtp_password: password autenticazione
|
||||
from_email: indirizzo mittente
|
||||
to_email: indirizzo destinatario
|
||||
subject: oggetto email
|
||||
body_text: testo plain
|
||||
body_html: testo HTML (opzionale)
|
||||
from_name: nome visualizzato mittente
|
||||
use_tls: usa SSL/TLS diretto (porta 465)
|
||||
use_starttls: usa STARTTLS (porta 587) – alternativo a use_tls
|
||||
timeout: timeout connessione in secondi
|
||||
|
||||
Raises:
|
||||
EmailSMTPError: in caso di errori di autenticazione, connessione o invio
|
||||
"""
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["Subject"] = subject
|
||||
msg["From"] = f"{from_name} <{from_email}>" if from_name else from_email
|
||||
msg["To"] = to_email
|
||||
msg["Date"] = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
|
||||
msg["X-Mailer"] = "PEChub/1.0"
|
||||
|
||||
msg.attach(MIMEText(body_text, "plain", "utf-8"))
|
||||
if body_html:
|
||||
msg.attach(MIMEText(body_html, "html", "utf-8"))
|
||||
|
||||
try:
|
||||
await aiosmtplib.send(
|
||||
msg,
|
||||
hostname=smtp_host,
|
||||
port=smtp_port,
|
||||
username=smtp_user,
|
||||
password=smtp_password,
|
||||
use_tls=use_tls,
|
||||
start_tls=use_starttls,
|
||||
timeout=timeout,
|
||||
)
|
||||
except aiosmtplib.SMTPAuthenticationError as exc:
|
||||
raise EmailSMTPError(
|
||||
f"Autenticazione SMTP fallita per {smtp_user}@{smtp_host}: {exc}",
|
||||
smtp_code=535,
|
||||
) from exc
|
||||
except aiosmtplib.SMTPConnectError as exc:
|
||||
raise EmailSMTPError(
|
||||
f"Connessione SMTP fallita a {smtp_host}:{smtp_port}: {exc}"
|
||||
) from exc
|
||||
except aiosmtplib.SMTPServerDisconnected as exc:
|
||||
raise EmailSMTPError(
|
||||
f"Server SMTP {smtp_host} ha chiuso la connessione: {exc}"
|
||||
) from exc
|
||||
except aiosmtplib.SMTPException as exc:
|
||||
raise EmailSMTPError(f"Errore SMTP: {exc}") from exc
|
||||
except Exception as exc:
|
||||
raise EmailSMTPError(f"Errore invio email: {exc}") from exc
|
||||
|
||||
|
||||
async def send_test_email(
|
||||
smtp_host: str,
|
||||
smtp_port: int,
|
||||
smtp_user: str,
|
||||
smtp_password: str,
|
||||
from_email: str,
|
||||
to_email: str,
|
||||
channel_name: str = "PEChub",
|
||||
from_name: str = "PEChub Notifiche",
|
||||
use_tls: bool = True,
|
||||
use_starttls: bool = False,
|
||||
) -> None:
|
||||
"""
|
||||
Invia un'email di test per verificare la configurazione del canale.
|
||||
|
||||
Raises:
|
||||
EmailSMTPError: se la connessione o l'autenticazione falliscono
|
||||
"""
|
||||
ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
subject = f"[PEChub] Test canale email: {channel_name}"
|
||||
body_text = (
|
||||
f"PEChub – Test canale Email\n\n"
|
||||
f"Il canale '{channel_name}' e' configurato correttamente.\n\n"
|
||||
f"Data/ora: {ts}\n"
|
||||
f"Destinatario: {to_email}"
|
||||
)
|
||||
body_html = (
|
||||
f"<h2>PEChub – Test canale Email</h2>"
|
||||
f"<p>Il canale <strong>{channel_name}</strong> e' configurato correttamente.</p>"
|
||||
f"<p>Data/ora: <em>{ts}</em><br>"
|
||||
f"Destinatario: {to_email}</p>"
|
||||
f"<hr><p style='font-size:11px;color:#888'>Inviato da PEChub Notification Engine</p>"
|
||||
)
|
||||
await send_email_notification(
|
||||
smtp_host=smtp_host,
|
||||
smtp_port=smtp_port,
|
||||
smtp_user=smtp_user,
|
||||
smtp_password=smtp_password,
|
||||
from_email=from_email,
|
||||
to_email=to_email,
|
||||
subject=subject,
|
||||
body_text=body_text,
|
||||
body_html=body_html,
|
||||
from_name=from_name,
|
||||
use_tls=use_tls,
|
||||
use_starttls=use_starttls,
|
||||
)
|
||||
Reference in New Issue
Block a user