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
This commit is contained in:
Goffi 2024-09-28 15:59:12 +02:00
commit 08cd3fd587

View file

@ -51,6 +51,7 @@ from libervia.backend.plugins.plugin_xep_0033 import (
)
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 @@ email_pattern = re.compile(r"[^@]+@[^@]+\.[^@]+")
class SendMailExtra(BaseModel):
addresses: AddressesData | None = None
headers: HeadersData | None = None
class EmailGatewayComponent:
@ -103,6 +105,7 @@ class EmailGatewayComponent:
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 @@ class EmailGatewayComponent:
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 @@ class EmailGatewayComponent:
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 @@ class EmailGatewayComponent:
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 @@ class EmailGatewayComponent:
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 @@ class EmailGatewayComponent:
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 @@ class EmailGatewayComponent:
):
addresses_data.noreply = True
break
extra = {}
if (
not addresses_data.replyto
@ -702,7 +722,7 @@ class EmailGatewayComponent:
):
# 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 @@ class EmailGatewayComponent:
# 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(