Add RFC email headers to report messages
This commit is contained in:
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import smtplib
|
import smtplib
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
|
from email.utils import formatdate, make_msgid, parseaddr
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from pve_backup_report.config import EmailConfig
|
from pve_backup_report.config import EmailConfig
|
||||||
@@ -47,6 +48,9 @@ def build_report_message(config: EmailConfig, pdf_path: Path) -> EmailMessage:
|
|||||||
message["Subject"] = config.subject
|
message["Subject"] = config.subject
|
||||||
message["From"] = config.smtp_from or ""
|
message["From"] = config.smtp_from or ""
|
||||||
message["To"] = ", ".join(config.smtp_to)
|
message["To"] = ", ".join(config.smtp_to)
|
||||||
|
message["Date"] = formatdate(localtime=True)
|
||||||
|
message["Message-ID"] = make_msgid(domain=message_id_domain(config.smtp_from))
|
||||||
|
message["Auto-Submitted"] = "auto-generated"
|
||||||
message.set_content(
|
message.set_content(
|
||||||
"Bonjour,\n\n"
|
"Bonjour,\n\n"
|
||||||
"Veuillez trouver ci-joint le rapport de sauvegardes Proxmox VE.\n\n"
|
"Veuillez trouver ci-joint le rapport de sauvegardes Proxmox VE.\n\n"
|
||||||
@@ -61,6 +65,16 @@ def build_report_message(config: EmailConfig, pdf_path: Path) -> EmailMessage:
|
|||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def message_id_domain(address: str | None) -> str | None:
|
||||||
|
if address is None:
|
||||||
|
return None
|
||||||
|
parsed_address = parseaddr(address)[1]
|
||||||
|
if "@" not in parsed_address:
|
||||||
|
return None
|
||||||
|
domain = parsed_address.rsplit("@", 1)[1].strip()
|
||||||
|
return domain or None
|
||||||
|
|
||||||
|
|
||||||
def authenticate_and_send(
|
def authenticate_and_send(
|
||||||
smtp: smtplib.SMTP | smtplib.SMTP_SSL,
|
smtp: smtplib.SMTP | smtplib.SMTP_SSL,
|
||||||
config: EmailConfig,
|
config: EmailConfig,
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from pve_backup_report.config import EmailConfig
|
from pve_backup_report.config import EmailConfig
|
||||||
from pve_backup_report.email_report import build_report_message, send_report_email
|
from pve_backup_report.email_report import (
|
||||||
|
build_report_message,
|
||||||
|
message_id_domain,
|
||||||
|
send_report_email,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_build_report_message_attaches_pdf(tmp_path: Path) -> None:
|
def test_build_report_message_attaches_pdf(tmp_path: Path) -> None:
|
||||||
@@ -20,6 +24,9 @@ def test_build_report_message_attaches_pdf(tmp_path: Path) -> None:
|
|||||||
assert message["Subject"] == "Rapport PVE"
|
assert message["Subject"] == "Rapport PVE"
|
||||||
assert message["From"] == "report@example.invalid"
|
assert message["From"] == "report@example.invalid"
|
||||||
assert message["To"] == "admin@example.invalid"
|
assert message["To"] == "admin@example.invalid"
|
||||||
|
assert message["Date"]
|
||||||
|
assert message["Message-ID"].endswith("@example.invalid>")
|
||||||
|
assert message["Auto-Submitted"] == "auto-generated"
|
||||||
attachments = list(message.iter_attachments())
|
attachments = list(message.iter_attachments())
|
||||||
assert len(attachments) == 1
|
assert len(attachments) == 1
|
||||||
assert attachments[0].get_filename() == "rapport.pdf"
|
assert attachments[0].get_filename() == "rapport.pdf"
|
||||||
@@ -27,6 +34,13 @@ def test_build_report_message_attaches_pdf(tmp_path: Path) -> None:
|
|||||||
assert attachments[0].get_payload(decode=True) == b"%PDF-1.7"
|
assert attachments[0].get_payload(decode=True) == b"%PDF-1.7"
|
||||||
|
|
||||||
|
|
||||||
|
def test_message_id_domain_uses_sender_domain() -> None:
|
||||||
|
assert message_id_domain("PVE Report <pve@example.invalid>") == "example.invalid"
|
||||||
|
assert message_id_domain("pve@example.invalid") == "example.invalid"
|
||||||
|
assert message_id_domain("invalid") is None
|
||||||
|
assert message_id_domain(None) is None
|
||||||
|
|
||||||
|
|
||||||
def test_send_report_email_uses_starttls_and_auth(tmp_path: Path, monkeypatch) -> None:
|
def test_send_report_email_uses_starttls_and_auth(tmp_path: Path, monkeypatch) -> None:
|
||||||
pdf_path = tmp_path / "rapport.pdf"
|
pdf_path = tmp_path / "rapport.pdf"
|
||||||
pdf_path.write_bytes(b"%PDF-1.7")
|
pdf_path.write_bytes(b"%PDF-1.7")
|
||||||
|
|||||||
Reference in New Issue
Block a user