Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid HTML tags in plain text part of notification emails #640

Merged
merged 8 commits into from
May 8, 2024
3 changes: 0 additions & 3 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,6 @@ services:
dev:
aliases:
- mail
ports:
- "5005:5005"
- "5006:5006"

volumes:
home:
Expand Down
21 changes: 8 additions & 13 deletions docker/mail.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
FROM golang:rc-alpine
RUN apk add --no-cache git
RUN apk add --no-cache gcc
RUN apk add --no-cache musl-dev
RUN git clone "https://github.com/jamillosantos/mailslurper.git" /opt/mailslurper
WORKDIR /opt/mailslurper/cmd/mailslurper
RUN go get github.com/mjibson/esc
RUN cd /opt/mailslurper/cmd/mailslurper
COPY ./mailslurper.conf config.json
RUN go get
RUN go generate
RUN go build
ENTRYPOINT ["/opt/mailslurper/cmd/mailslurper/mailslurper"]
FROM debian:stable-slim

RUN apt-get update && apt-get install -y python3 python3-aiosmtpd python3-termcolor

WORKDIR /opt/mail
COPY mail.py mail.py

ENTRYPOINT ["python3", "mail.py"]
49 changes: 49 additions & 0 deletions docker/mail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import asyncio
import email
import email.policy
import sys

from aiosmtpd.controller import Controller
from termcolor import cprint


class PycroftDebugging:
COLOR_HEADER = "blue"
COLOR_CONTENT_BORDER = "magenta"

async def handle_DATA(self, server, session, envelope):
message = email.message_from_bytes(envelope.content, policy=email.policy.default)

# Print headers
for key, value in message.items():
cprint(f"{key}: {value}", self.COLOR_HEADER)

# Print message parts, i.e. text/plain, text/html
for part in message.walk():
try:
content = part.get_content()
except KeyError:
continue

print()
content_type = part.get_content_type()
cprint(content_type, self.COLOR_CONTENT_BORDER)
cprint("⌄" * len(content_type), self.COLOR_CONTENT_BORDER)
print(content)
cprint("⌃" * len(content_type), self.COLOR_CONTENT_BORDER)

print()
sys.stdout.flush()

return "250 Message accepted for delivery"


controller = Controller(PycroftDebugging(), hostname="0.0.0.0", port=2500)
controller.start()

loop = asyncio.get_event_loop()
try:
loop.run_forever()
finally:
loop.close()
controller.stop()
27 changes: 0 additions & 27 deletions docker/mailslurper.conf

This file was deleted.

4 changes: 4 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,7 @@ _stop_all:

_up +containers:
{{ drc }} up --wait {{ containers }}

show_emails:
{{ drc }} --progress=none up -d dev-celery-worker dev-mail
{{ drc }} logs --no-log-prefix -f dev-mail
15 changes: 0 additions & 15 deletions pycroft/lib/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,18 +248,3 @@ def send_template_mails(
from pycroft.task import send_mails_async

send_mails_async.delay(mails)


def send_plain_mails(email_addresses: list[str], subject: str, body_plain: str) -> None:
mails = []

for addr in email_addresses:
mail = Mail(to_name='',
to_address=addr,
subject=subject,
body_plain=body_plain)
mails.append(mail)

from pycroft.task import send_mails_async

send_mails_async.delay(mails)
11 changes: 11 additions & 0 deletions pycroft/templates/mail/base.html.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{%- set links = [] -%}
{%- import "macros/link.html" as link with context -%}
{%- if mode == 'html' -%}
<pre>
{% endif %}
{%- block body -%}{%- endblock -%}

{{ link.render_link_list() }}
{%- if mode == 'html' -%}
</pre>
{%- endif -%}
4 changes: 2 additions & 2 deletions pycroft/templates/mail/macros/link.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{%- macro render_link(text, url, mode) -%}
{%- macro render_link(text, url) -%}
{%- if mode == 'html' -%}
<a href="{{ url }}">{{ text }}</a>
{%- else -%}
{{ text }} [{{ links|length }}]{{ '' if links.append(url) }}
{%- endif -%}
{%- endmacro -%}

{%- macro render_link_list(mode) -%}
{% macro render_link_list() -%}
{%- if mode != 'html' -%}
{%- for n in range(links|length) -%}
[{{ n }}] {{ links[n] }}
Expand Down
5 changes: 3 additions & 2 deletions pycroft/templates/mail/member_negative_balance.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<pre>
{%- extends "base.html.j2" -%}
{%- block body -%}
* English version below *

Hallo {{ user.name }},
Expand Down Expand Up @@ -97,4 +98,4 @@
[4] Office hours: https://agdsn.de/sipa/pages/support/contacts
[5] Finance constitution:
https://agdsn.de/sipa/documents/legal/beitragsordnung.pdf
</pre>
{%- endblock -%}
7 changes: 3 additions & 4 deletions pycroft/templates/mail/member_request_denied.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<pre>
{%- extends "base.html.j2" -%}
{%- block body -%}
English version below!

---
Expand Down Expand Up @@ -30,6 +31,4 @@

Best Regards
Your AG DSN
</pre>


{%- endblock -%}
7 changes: 3 additions & 4 deletions pycroft/templates/mail/member_request_merged.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<pre>
{%- extends "base.html.j2" -%}
{%- block body -%}
English version below!

---
Expand Down Expand Up @@ -41,6 +42,4 @@

Best Regards
Your AG DSN
</pre>


{%- endblock -%}
7 changes: 3 additions & 4 deletions pycroft/templates/mail/member_request_pending.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<pre>
{%- extends "base.html.j2" -%}
{%- block body -%}
English version below!

---
Expand Down Expand Up @@ -70,6 +71,4 @@

Best Regards
Your AG DSN
</pre>


{%- endblock -%}
7 changes: 3 additions & 4 deletions pycroft/templates/mail/task_failed.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<pre>
{%- extends "base.html.j2" -%}
{%- block body -%}
Hallo Supportteam,

die geplante Pycroft {{ task.type }} Aufgabe #{{ task.id }} von {{ task.creator.name }}
Expand All @@ -15,6 +16,4 @@

Viele Grüße
Pycroft
</pre>


{%- endblock -%}
13 changes: 5 additions & 8 deletions pycroft/templates/mail/user_confirm_email.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{%- set links = [] -%}
{%- extends "base.html.j2" -%}
{%- import "macros/link.html" as link with context -%}
<pre>
{%- block body -%}
English version below!

---
Expand All @@ -9,26 +9,23 @@

bitte bestätige deine E-Mail-Adresse, indem du auf folgenden Link klickst:

{{ link.render_link(email_confirm_url, email_confirm_url, mode) }}
{{ email_confirm_url }}

Falls du dich nicht bei uns registriert hast, kannst du diese E-Mail ignorieren.

Viele Grüße
Deine AG DSN

{{ link.render_link_list(mode) }}
--

Hello {{ user.name }},

Please confirm your email address by clicking on the following link:

{{ link.render_link(email_confirm_url, email_confirm_url, mode) }}
{{ email_confirm_url }}

If you have not registered with us, you can ignore this email.

Best Regards
Your AG DSN

{{ link.render_link_list(mode) }}
</pre>
{%- endblock -%}
31 changes: 14 additions & 17 deletions pycroft/templates/mail/user_created.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{%- set links = [] -%}
{%- extends "base.html.j2" -%}
{%- import "macros/link.html" as link with context -%}

<pre>
{%- block body -%}
English version below!

---
Expand All @@ -21,32 +20,32 @@
Wenn du Interesse hast und mal einen Blick auf Technik werfen willst, die man
sonst eher nicht zu Gesicht bekommt, würden wir uns freuen dich bei einer unserer
Teamsitzungen begrüßen zu dürfen.
Wann, wo und wie die Sitzungen stattfinden, kannst du unserer {{ link.render_link("Teamübersicht", "https://agdsn.de/sipa/pages/about_us/teams", mode) }}
Wann, wo und wie die Sitzungen stattfinden, kannst du unserer {{ link.render_link("Teamübersicht", "https://agdsn.de/sipa/pages/about_us/teams") }}
entnehmen.

Deine Mitgliedschaft beginnt je nach gewählter Option entweder sofort oder
mit deinem Einzug in dein Wohnheimzimmer.
Den aktuellen Status deiner Mitgliedschaft kannst du in der {{ link.render_link("Usersuite", "https://agdsn.de/sipa/usersuite/", mode) }}
Den aktuellen Status deiner Mitgliedschaft kannst du in der {{ link.render_link("Usersuite", "https://agdsn.de/sipa/usersuite/") }}
einsehen.

Deine Nutzer-ID: {{ user_id }}
Dein Nutzername: {{ user.login }}

Bitte denke daran, den {{ link.render_link("Mitgliedsbeitrag", "https://agdsn.de/sipa/pages/membership/membership_contribution", mode) }} immer pünktlich
Bitte denke daran, den {{ link.render_link("Mitgliedsbeitrag", "https://agdsn.de/sipa/pages/membership/membership_contribution") }} immer pünktlich
(vor Ende des Monats) mit dem korrkten Verwendungszweck zu überweisen.
Es ist auch möglich für mehrere Monate aufeinmal zu bezahlen.

Mit deiner Mitgliedschaft erhälst du ein E-Mail Konto mit der Adresse {{ user.email_internal }}.
Standardmäßig werden alle E-Mails an deine angegebene Adresse weitergeleietet.
Diese Weiterleitung kannst du in der Usersuite deaktivieren, wenn du das Konto
eigenständig nutzen möchtest. Weitere Informationen findest du auf unserer {{ link.render_link("Internetseite", "https://agdsn.de/sipa/pages/service/email", mode) }}.
eigenständig nutzen möchtest. Weitere Informationen findest du auf unserer {{ link.render_link("Internetseite", "https://agdsn.de/sipa/pages/service/email") }}.

Weitere Schritte (u.a. zur Verwendung des Netzwerkes) findest du {{ link.render_link("hier", "https://agdsn.de/sipa/pages/membership/registration_account_created", mode) }}.
Weitere Schritte (u.a. zur Verwendung des Netzwerkes) findest du {{ link.render_link("hier", "https://agdsn.de/sipa/pages/membership/registration_account_created") }}.

Viele Grüße
Deine AG DSN

{{ link.render_link_list(mode) }}
{{ link.render_link_list() }}
--

Hello {{ user.name }},
Expand All @@ -61,28 +60,26 @@
network maintenance, software development and many more. Besides, you can add
some extra extracurricular activity to your CV and have the opportunity to see
and work with usually hidden technology.
We would be happy to welcome you with us. Be our guest at one of our {{ link.render_link("team meetings", "https://agdsn.de/sipa/pages/about_us/teams", mode) }}.
We would be happy to welcome you with us. Be our guest at one of our {{ link.render_link("team meetings", "https://agdsn.de/sipa/pages/about_us/teams") }}.

Depending on the chosen option, your membership starts either immediately or
with you moving into your dorm room.
You can check the current status of your membership in the {{ link.render_link("Usersuite", "https://agdsn.de/sipa/usersuite/", mode) }}.
You can check the current status of your membership in the {{ link.render_link("Usersuite", "https://agdsn.de/sipa/usersuite/") }}.

Your User-ID: {{ user_id }}
Your Username: {{ user.login }}

Please remember to transfer the {{ link.render_link("membership contribution", "https://agdsn.de/sipa/pages/membership/membership_contribution", mode) }}
Please remember to transfer the {{ link.render_link("membership contribution", "https://agdsn.de/sipa/pages/membership/membership_contribution") }}
always in time (before the end of the month) with the correct payment description.
It is also possible to pay for multiple months at once.

With your membership you will receive an email account with the address {{ user.email_internal }}.
By default, all emails will be forwarded to the address you specified.
You can disable this forwarding in the usersuite if you want to use the standalone.
For more information, please visit our {{ link.render_link("website", "https://agdsn.de/sipa/pages/service/email", mode) }}.
For more information, please visit our {{ link.render_link("website", "https://agdsn.de/sipa/pages/service/email") }}.

Further steps (including how to use the network) can be found {{ link.render_link("here", "https://agdsn.de/sipa/pages/membership/registration_account_created", mode) }}
Further steps (including how to use the network) can be found {{ link.render_link("here", "https://agdsn.de/sipa/pages/membership/registration_account_created") }}

Best Regards
Your AG DSN

{{ link.render_link_list(mode) }}
</pre>
{%- endblock -%}
Loading
Loading