Enhance newsletter functionality with contact email support

- Added support for a contact email in newsletter generation, allowing users to specify a reply-to address.
- Updated the SMTP settings to include a reply-to field in the configuration.
- Modified the newsletter templates to display the contact email in plain text and HTML formats.
- Improved the dashboard UI to allow users to set the reply-to address when configuring SMTP settings.
This commit is contained in:
smueller
2026-07-07 15:42:12 +02:00
parent 9a0871381a
commit 3d0f5e4f04
4 changed files with 62 additions and 10 deletions

View File

@@ -203,6 +203,7 @@ def create_plain_text(
period_label: str | None = None,
period: tuple[str, str] | None = None,
article_type: str = "all",
contact_email: str = "",
) -> str:
display = display or DEFAULT_DISPLAY
new_articles, edited_articles = split_articles_by_type(articles)
@@ -250,7 +251,7 @@ def create_plain_text(
]
)
lines.extend(_plain_editor_tip(editor_tip))
lines.append(_plain_footer(new_articles, edited_articles))
lines.append(_plain_footer(new_articles, edited_articles, contact_email))
return "\n".join(lines).strip()
if show_new:
@@ -267,7 +268,7 @@ def create_plain_text(
)
lines.append("")
lines.extend(_plain_editor_tip(editor_tip))
lines.append(_plain_footer(new_articles, edited_articles))
lines.append(_plain_footer(new_articles, edited_articles, contact_email))
return "\n".join(lines).strip()
@@ -296,6 +297,7 @@ def create_html(
period: tuple[str, str] | None = None,
article_type: str = "all",
month_label: str | None = None,
contact_email: str = "",
) -> str:
display = display or DEFAULT_DISPLAY
new_articles, edited_articles = split_articles_by_type(articles)
@@ -334,6 +336,15 @@ def create_html(
f'<strong style="color:{COLOR_HEADING};">Filter:</strong> Kategorie {escape(category.strip())}</p></td></tr>'
)
if contact_email.strip():
ce = escape(contact_email.strip())
contact_html = (
f'Fragen oder ein Themenwunsch? Meldet euch gern beim '
f'<a href="mailto:{ce}" style="color:{COLOR_TK_ORANGE};text-decoration:underline;">Wiki-Team</a>.'
)
else:
contact_html = "Fragen oder ein Themenwunsch? Meldet euch gern beim Wiki-Team."
return f"""<!DOCTYPE html>
<html lang="de" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
@@ -411,7 +422,7 @@ def create_html(
<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0">
<tr>
<td style="font-family:{FONT};font-size:15px;line-height:24px;color:{COLOR_TEXT};">
Fragen oder ein Themenwunsch? Meldet euch gern beim Wiki-Team.<br><br>
{contact_html}<br><br>
Viele Grüße<br>
Euer Thomas-Krenn-Wiki Team
</td>
@@ -679,6 +690,7 @@ def create_outlook_html(
period: tuple[str, str] | None = None,
article_type: str = "all",
month_label: str | None = None,
contact_email: str = "",
) -> str:
"""Word/Outlook-kompatibles HTML mit font-Tags und bgcolor (überlebt Einfügen in Outlook)."""
display = display or DEFAULT_DISPLAY
@@ -726,6 +738,19 @@ def create_outlook_html(
editor_tip_row = _outlook_editor_tip(editor_tip)
if contact_email.strip():
contact_inner = (
f'{_outlook_font("Fragen oder ein Themenwunsch? Meldet euch gern beim Wiki-Team: ", size="1")}'
f'{_outlook_link(contact_email.strip(), f"mailto:{contact_email.strip()}", color=OUTLOOK_ORANGE, bold=False)}'
)
contact_row = f"""<tr>
<td {_outlook_td_attrs(extra_style="padding:12px 0 0;")}>
{contact_inner}
</td>
</tr>"""
else:
contact_row = ""
return f"""<!DOCTYPE html>
<html lang="de" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word">
<head>
@@ -785,6 +810,7 @@ def create_outlook_html(
{_outlook_cta(WIKI_HOME_URL, "Zum Thomas-Krenn-Wiki →")}
</td>
</tr>
{contact_row}
<tr>
<td {_outlook_td_attrs(extra_style=f"padding:16px 0 0;border-top:1px solid {OUTLOOK_BORDER};")}>
{_outlook_font(f"Automatisch erstellter interner Newsletter · Nur für den Gebrauch bei {ORG_NAME}", color=OUTLOOK_MUTED, size="1")}
@@ -932,8 +958,15 @@ def _plain_item(idx: int, item: dict[str, Any], display: DisplayOptions) -> list
return lines
def _plain_footer(new_articles: list[dict[str, Any]], edited_articles: list[dict[str, Any]]) -> str:
def _plain_footer(
new_articles: list[dict[str, Any]],
edited_articles: list[dict[str, Any]],
contact_email: str = "",
) -> str:
total = len(new_articles) + len(edited_articles)
contact_lines = []
if contact_email.strip():
contact_lines = [f"Fragen oder ein Themenwunsch? E-Mail an das Wiki-Team: {contact_email.strip()}", ""]
return "\n".join(
[
SUBLINE,
@@ -945,6 +978,7 @@ def _plain_footer(new_articles: list[dict[str, Any]], edited_articles: list[dict
"",
f"Wiki: {WIKI_HOME_URL}",
"",
*contact_lines,
SUBLINE,
"Dieser Newsletter wurde automatisch erstellt und ist nur für den internen",
f"Gebrauch bei {ORG_NAME} bestimmt.",