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:
parent
5ccec8f755
commit
08cd3fd587
1 changed files with 47 additions and 7 deletions
|
|
@ -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(
|
||||
|
|
|
|||
Loading…
Reference in a new issue