From 33dd694ba1fad1a2a85d7178115d728991b63a3f Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Mon, 1 Jun 2026 00:04:36 +0200
Subject: [PATCH] fix: Outlook email UTF-8 charset for umlauts - add meta
charset to HTML body
Co-authored-by: Cursor
---
.../connectors/providerMsft/connectorMsft.py | 18 ++++++++++++++++--
.../actions/composeAndDraftEmailWithContext.py | 8 ++++----
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/modules/connectors/providerMsft/connectorMsft.py b/modules/connectors/providerMsft/connectorMsft.py
index 49f6fdaa..52e50af2 100644
--- a/modules/connectors/providerMsft/connectorMsft.py
+++ b/modules/connectors/providerMsft/connectorMsft.py
@@ -62,7 +62,7 @@ async def _makeGraphCall(
) -> Dict[str, Any]:
"""Execute a single Microsoft Graph API call."""
url = f"{_GRAPH_BASE}/{endpoint.lstrip('/')}"
- contentType = "application/json"
+ contentType = "application/json; charset=utf-8"
if method == "PUT" and isinstance(data, bytes):
contentType = "application/octet-stream"
headers = {
@@ -271,6 +271,17 @@ class SharepointAdapter(_GraphApiMixin, ServiceAdapter):
# Outlook Adapter
# ---------------------------------------------------------------------------
+_CHARSET_META = ''
+
+def _ensureHtmlCharset(html: str) -> str:
+ """Ensure HTML body has a charset meta tag so Outlook renders UTF-8 correctly."""
+ if "charset" in html.lower():
+ return html
+ if html.strip().lower().startswith("", f"{_CHARSET_META}", 1)
+ return f"{_CHARSET_META}{html}"
+
+
class OutlookAdapter(_GraphApiMixin, ServiceAdapter):
"""ServiceAdapter for Outlook (mail, calendar) via Microsoft Graph."""
@@ -433,9 +444,12 @@ class OutlookAdapter(_GraphApiMixin, ServiceAdapter):
attachments: list of {"name": str, "contentBytes": str (base64), "contentType": str}
"""
+ content = body
+ if bodyType.upper() == "HTML":
+ content = _ensureHtmlCharset(body)
message: Dict[str, Any] = {
"subject": subject,
- "body": {"contentType": bodyType, "content": body},
+ "body": {"contentType": bodyType, "content": content},
"toRecipients": [{"emailAddress": {"address": addr}} for addr in to],
}
if cc:
diff --git a/modules/workflows/methods/methodOutlook/actions/composeAndDraftEmailWithContext.py b/modules/workflows/methods/methodOutlook/actions/composeAndDraftEmailWithContext.py
index a191e84b..22c5ff62 100644
--- a/modules/workflows/methods/methodOutlook/actions/composeAndDraftEmailWithContext.py
+++ b/modules/workflows/methods/methodOutlook/actions/composeAndDraftEmailWithContext.py
@@ -261,16 +261,16 @@ Return JSON:
"Content-Type": "application/json"
}
- # Clean and format body content
cleaned_body = body.strip()
+ _CHARSET_META = ''
- # Check if body is already HTML
if cleaned_body.startswith('') or cleaned_body.startswith('') or '
' in cleaned_body:
html_body = cleaned_body
+ if "charset" not in html_body.lower():
+ html_body = html_body.replace("", f"{_CHARSET_META}", 1) if "" in html_body else f"{_CHARSET_META}{html_body}"
else:
- # Convert plain text to proper HTML formatting
html_body = cleaned_body.replace('\n', '
')
- html_body = f"{html_body}"
+ html_body = f"{_CHARSET_META}{html_body}"
# Build the email message
message = {