# HG changeset patch # User Goffi # Date 1727531952 -7200 # Node ID 055930cc81f918d14dd1b68c1f9d99a5e3e3c7ba # Parent 1795bfcc38e7fdfd280a16cdbed2c8a18aa6fdeb 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 diff -r 1795bfcc38e7 -r 055930cc81f9 libervia/backend/plugins/plugin_comp_email_gateway/__init__.py --- 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(