feat: provide governed notification email delivery
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from email.message import EmailMessage
|
||||
from email.utils import formatdate, make_msgid
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from govoplan_core.core.mail import NotificationMailDeliveryRequest
|
||||
from govoplan_core.core.modules import ModuleContext
|
||||
from govoplan_mail.backend.mail_profiles import (
|
||||
MailProfileError,
|
||||
@@ -554,3 +557,102 @@ def delivery_outbox_capability(context: ModuleContext):
|
||||
|
||||
configure_runtime(settings=context.settings)
|
||||
return MailDeliveryOutboxCapability()
|
||||
|
||||
|
||||
class MailNotificationDeliveryCapability:
|
||||
"""Submit notification email to the Mail-owned durable outbox."""
|
||||
|
||||
def submit_notification_mail(
|
||||
self,
|
||||
session: Session,
|
||||
request: NotificationMailDeliveryRequest,
|
||||
) -> dict[str, object]:
|
||||
profile_id = str(request.mail_profile_id or "").strip()
|
||||
from_address = str(request.from_address or "").strip()
|
||||
if not profile_id or not from_address:
|
||||
return {
|
||||
"status": "paused",
|
||||
"provider": "mail.notificationDelivery",
|
||||
"error": (
|
||||
"Notification email requires a Mail profile and sender "
|
||||
"selected by tenant policy."
|
||||
),
|
||||
}
|
||||
try:
|
||||
transport = campaign_profile_delivery_summary(
|
||||
session,
|
||||
tenant_id=request.tenant_id,
|
||||
profile_id=profile_id,
|
||||
smtp_server_id=request.smtp_server_id,
|
||||
smtp_credential_id=request.smtp_credential_id,
|
||||
)
|
||||
except MailProfileError:
|
||||
return {
|
||||
"status": "paused",
|
||||
"provider": "mail.notificationDelivery",
|
||||
"error": (
|
||||
"The selected notification Mail profile is unavailable or "
|
||||
"blocked by effective policy."
|
||||
),
|
||||
}
|
||||
if not transport.get("smtp_available"):
|
||||
return {
|
||||
"status": "paused",
|
||||
"provider": "mail.notificationDelivery",
|
||||
"error": "The selected notification Mail profile has no usable SMTP transport.",
|
||||
}
|
||||
|
||||
message = EmailMessage()
|
||||
message["Date"] = formatdate(localtime=True)
|
||||
message["Message-ID"] = make_msgid()
|
||||
message["Subject"] = request.subject
|
||||
message["From"] = from_address
|
||||
message["To"] = request.recipient
|
||||
message.set_content(request.body_text)
|
||||
if request.body_html:
|
||||
message.add_alternative(request.body_html, subtype="html")
|
||||
|
||||
from govoplan_mail.backend.delivery_outbox import submit_delivery_command
|
||||
|
||||
command = submit_delivery_command(
|
||||
session,
|
||||
tenant_id=request.tenant_id,
|
||||
command_type="notification",
|
||||
source_module="notifications",
|
||||
source_resource_type="notification",
|
||||
source_resource_id=request.notification_id,
|
||||
source_version_id=None,
|
||||
idempotency_key=f"notification:{request.notification_id}",
|
||||
profile_id=profile_id,
|
||||
smtp_server_id=(
|
||||
str(transport.get("smtp_server_id"))
|
||||
if transport.get("smtp_server_id")
|
||||
else request.smtp_server_id
|
||||
),
|
||||
smtp_credential_id=(
|
||||
str(transport.get("smtp_credential_id"))
|
||||
if transport.get("smtp_credential_id")
|
||||
else request.smtp_credential_id
|
||||
),
|
||||
message_bytes=bytes(message),
|
||||
envelope_from=from_address,
|
||||
envelope_recipients=[request.recipient],
|
||||
from_header=from_address,
|
||||
expected_smtp_transport_revision=str(
|
||||
transport["smtp_transport_revision"]
|
||||
),
|
||||
)
|
||||
return {
|
||||
"status": "accepted",
|
||||
"provider": "mail.delivery_outbox",
|
||||
"external_message_id": command["id"],
|
||||
"delivery_status": command["status"],
|
||||
"duplicate": bool(command.get("duplicate")),
|
||||
}
|
||||
|
||||
|
||||
def notification_delivery_capability(
|
||||
context: ModuleContext,
|
||||
) -> MailNotificationDeliveryCapability:
|
||||
configure_runtime(settings=context.settings)
|
||||
return MailNotificationDeliveryCapability()
|
||||
|
||||
Reference in New Issue
Block a user