changeset 4317:055930cc81f9

component email gateway: Add support for XEP-0131 headers: Some email headers (`Keywords` and `Importance` for now) are converted between XMPP and email. rel 451
author Goffi <goffi@goffi.org>
date Sat, 28 Sep 2024 15:59:12 +0200
parents 1795bfcc38e7
children 27bb22eace65
files libervia/backend/plugins/plugin_comp_email_gateway/__init__.py
diffstat 1 files changed, 47 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/libervia/backend/plugins/plugin_comp_email_gateway/__init__.py	Sat Sep 28 15:57:31 2024 +0200
+++ b/libervia/backend/plugins/plugin_comp_email_gateway/__init__.py	Sat Sep 28 15:59:12 2024 +0200
@@ -51,6 +51,7 @@
 )
 from libervia.backend.plugins.plugin_xep_0077 import XEP_0077
 from libervia.backend.plugins.plugin_xep_0106 import XEP_0106
+from libervia.backend.plugins.plugin_xep_0131 import XEP_0131, HeadersData, Urgency
 from libervia.backend.tools.utils import aio
 
 from .models import Credentials, UserData
@@ -87,6 +88,7 @@
 
 class SendMailExtra(BaseModel):
     addresses: AddressesData | None = None
+    headers: HeadersData | None = None
 
 
 class EmailGatewayComponent:
@@ -103,6 +105,7 @@
             self._on_registration_form, self._on_registration_submit
         )
         self._e = cast(XEP_0106, host.plugins["XEP-0106"])
+        self._shim = cast(XEP_0131, host.plugins["XEP-0131"])
         # TODO: For the moment, all credentials are kept in cache; we should only keep the
         #   X latest.
         self.users_data: dict[jid.JID, UserData] = {}
@@ -192,7 +195,7 @@
         if client != self.client:
             return mess_data
         from_jid = mess_data["from"].userhostJID()
-        extra = None
+        extra_kw = {}
         if mess_data["type"] not in ("chat", "normal"):
             log.warning(f"ignoring message with unexpected type: {mess_data}")
             return mess_data
@@ -206,7 +209,7 @@
                 return mess_data
             else:
                 to_email = None
-                extra = SendMailExtra(addresses=addresses)
+                extra_kw["addresses"] = addresses
         else:
             try:
                 to_email = self._e.unescape(mess_data["to"].user)
@@ -215,6 +218,11 @@
                     f'Invalid "to" JID, can\'t send message: {message_elt.toXml()}.'
                 )
 
+        self._shim.move_keywords_to_headers(mess_data["extra"])
+        headers = mess_data["extra"].get("headers")
+        if headers:
+            extra_kw["headers"] = headers
+
         try:
             body_lang, body = next(iter(mess_data["message"].items()))
         except (KeyError, StopIteration):
@@ -235,7 +243,7 @@
                 to_email=to_email,
                 body=body,
                 subject=subject,
-                extra=extra,
+                extra=SendMailExtra(**extra_kw) if extra_kw else None,
             )
         except exceptions.UnknownEntityError:
             log.warning(f"Can't send message, user {from_jid} is not registered.")
@@ -361,6 +369,17 @@
 
         sender_domain = credentials["user_email"].split("@", 1)[-1]
 
+        if extra.headers:
+            if extra.headers.keywords:
+                msg["Keywords"] = extra.headers.keywords
+            if extra.headers.urgency:
+                urgency = extra.headers.urgency
+                if urgency == Urgency.medium:
+                    importance = "normal"
+                else:
+                    importance = urgency
+                msg["Importance"] = importance
+
         await smtp.sendmail(
             credentials["smtp_host"].encode(),
             credentials["user_email"].encode(),
@@ -692,6 +711,7 @@
             ):
                 addresses_data.noreply = True
                 break
+        extra = {}
 
         if (
             not addresses_data.replyto
@@ -702,7 +722,7 @@
         ):
             # The main recipient is the only one, and there is no other metadata: there is
             # no need to add addresses metadata.
-            extra = None
+            pass
         else:
             for address in addresses_data.addresses:
                 if address.jid and (
@@ -712,9 +732,29 @@
                     # other JID addresses will have to be delivered by us.
                     address.delivered = True
 
-            extra = {
-                "addresses": addresses_data.model_dump(mode="json", exclude_none=True)
-            }
+            extra["addresses"] = addresses_data.model_dump(mode="json", exclude_none=True)
+
+        # We look for interesting headers
+        headers = {}
+        keywords_headers = email.get_all("keywords")
+        if keywords_headers:
+            keywords = ",".join(keywords_headers)
+            headers["keywords"] = keywords
+
+        importance = email["importance"]
+        if importance:
+            # We convert to urgency
+            if importance in ("low", "high"):
+                headers["urgency"] = importance
+            elif importance == "normal":
+                headers["urgency"] = "medium"
+            else:
+                log.warning("Ignoring invalid importance header: {importance!r}")
+
+        if headers:
+            extra["headers"] = HeadersData(**headers).model_dump(
+                mode="json", exclude_none=True
+            )
 
         client = self.client.get_virtual_client(from_jid)
         await client.sendMessage(