diff --git a/changedetectionio/notification/email_helpers.py b/changedetectionio/notification/email_helpers.py
new file mode 100644
index 00000000..c653db37
--- /dev/null
+++ b/changedetectionio/notification/email_helpers.py
@@ -0,0 +1,46 @@
+def as_monospaced_html_email(content: str, title: str) -> str:
+ """
+ Wraps `content` in a minimal, email-safe HTML template
+ that forces monospace rendering across Gmail, Hotmail, Apple Mail, etc.
+
+ Args:
+ content: The body text (plain text or HTML-like).
+ convert_newlines: If True, replaces '\n' with '
' for display.
+
+ Returns:
+ A complete HTML document string suitable for sending as an email body.
+ """
+
+ # All line feed types should be removed and then this function should only be fed
's
+ # Then it works with our
styling without double linefeeds
+ content = content.translate(str.maketrans('', '', '\r\n'))
+
+ if title:
+ import html
+ title = html.escape(title)
+ else:
+ title = ''
+ # 2. Full email-safe HTML
+ html_email = f"""
+
+
+
+
+
+
+ {title}
+
+
+
+ {content}
+
+
+"""
+ return html_email
\ No newline at end of file
diff --git a/changedetectionio/notification/handler.py b/changedetectionio/notification/handler.py
index 617b9608..33827f45 100644
--- a/changedetectionio/notification/handler.py
+++ b/changedetectionio/notification/handler.py
@@ -6,6 +6,7 @@ from loguru import logger
from urllib.parse import urlparse
from .apprise_plugin.assets import apprise_asset, APPRISE_AVATAR_URL
from .apprise_plugin.custom_handlers import SUPPORTED_HTTP_METHODS
+from .email_helpers import as_monospaced_html_email
from ..diff import HTML_REMOVED_STYLE, REMOVED_PLACEMARKER_OPEN, REMOVED_PLACEMARKER_CLOSED, ADDED_PLACEMARKER_OPEN, HTML_ADDED_STYLE, \
ADDED_PLACEMARKER_CLOSED, CHANGED_INTO_PLACEMARKER_OPEN, CHANGED_INTO_PLACEMARKER_CLOSED, CHANGED_PLACEMARKER_OPEN, \
CHANGED_PLACEMARKER_CLOSED, HTML_CHANGED_STYLE, HTML_CHANGED_INTO_STYLE
@@ -304,7 +305,7 @@ def process_notification(n_object: NotificationContextData, datastore):
# Could have arrived at any stage, so we dont end up running .escape on it
if 'html' in requested_output_format:
- n_body = n_body.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '
\n')
+ n_body = n_body.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '
\r\n')
else:
# Markup, text types etc
n_body = n_body.replace(CUSTOM_LINEBREAK_PLACEHOLDER, '\r\n')
@@ -314,6 +315,15 @@ def process_notification(n_object: NotificationContextData, datastore):
'url': url})
apobj.add(url)
+ # Enforce monospace output for PLAINTEXT Document going to a HTML style notification
+ watch_mime_type = n_object.get('watch_mime_type')
+ if watch_mime_type and 'text/' in watch_mime_type.lower() and not 'html' in watch_mime_type.lower():
+ if 'html' in requested_output_format:
+ # Since they likely want HTML style notifications but of a Plain-text document, lets wrap the body
+ if not '