mirror of
https://github.com/simple-login/app.git
synced 2024-11-13 07:31:12 +01:00
Merge pull request #122 from simple-login/unsubscribe
Support one-click unsubscribe
This commit is contained in:
commit
64eed21cf0
4 changed files with 92 additions and 5 deletions
|
@ -90,6 +90,9 @@ else:
|
|||
# disable the alias suffix, i.e. the ".random_word" part
|
||||
DISABLE_ALIAS_SUFFIX = "DISABLE_ALIAS_SUFFIX" in os.environ
|
||||
|
||||
# the email address that receives all unsubscription request
|
||||
UNSUBSCRIBER = os.environ.get("UNSUBSCRIBER")
|
||||
|
||||
DKIM_PRIVATE_KEY_PATH = get_abs_path(os.environ["DKIM_PRIVATE_KEY_PATH"])
|
||||
DKIM_PUBLIC_KEY_PATH = get_abs_path(os.environ["DKIM_PUBLIC_KEY_PATH"])
|
||||
DKIM_SELECTOR = b"dkim"
|
||||
|
|
|
@ -52,6 +52,7 @@ from app.config import (
|
|||
URL,
|
||||
ALIAS_DOMAINS,
|
||||
POSTFIX_SUBMISSION_TLS,
|
||||
UNSUBSCRIBER,
|
||||
)
|
||||
from app.email_utils import (
|
||||
send_email,
|
||||
|
@ -459,11 +460,15 @@ def handle_forward(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> (bool, s
|
|||
add_or_replace_header(msg, "To", to_header.strip())
|
||||
|
||||
# add List-Unsubscribe header
|
||||
unsubscribe_link = f"{URL}/dashboard/unsubscribe/{alias.id}"
|
||||
add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>")
|
||||
add_or_replace_header(
|
||||
msg, "List-Unsubscribe-Post", "List-Unsubscribe=One-Click"
|
||||
)
|
||||
if UNSUBSCRIBER:
|
||||
unsubscribe_link = f"mailto:{UNSUBSCRIBER}?subject={alias.id}="
|
||||
add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>")
|
||||
else:
|
||||
unsubscribe_link = f"{URL}/dashboard/unsubscribe/{alias.id}"
|
||||
add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>")
|
||||
add_or_replace_header(
|
||||
msg, "List-Unsubscribe-Post", "List-Unsubscribe=One-Click"
|
||||
)
|
||||
|
||||
add_dkim_signature(msg, EMAIL_DOMAIN)
|
||||
|
||||
|
@ -743,6 +748,54 @@ def handle_bounce(
|
|||
)
|
||||
|
||||
|
||||
def handle_unsubscribe(envelope):
|
||||
message_data = envelope.content.decode("utf8", errors="replace")
|
||||
msg = Parser(policy=SMTPUTF8).parsestr(message_data)
|
||||
|
||||
# format: alias_id:
|
||||
subject = msg["Subject"]
|
||||
try:
|
||||
alias_id = int(subject[:-1])
|
||||
alias = Alias.get(alias_id)
|
||||
except Exception:
|
||||
LOG.warning("Cannot parse alias from subject %s", msg["Subject"])
|
||||
return "550 SL ignored"
|
||||
|
||||
if not alias:
|
||||
LOG.warning("No such alias %s", alias_id)
|
||||
return "550 SL ignored"
|
||||
|
||||
# This sender cannot unsubscribe
|
||||
if alias.mailbox_email() != envelope.mail_from:
|
||||
LOG.d("%s cannot disable alias %s", envelope.mail_from, alias)
|
||||
return "550 SL ignored"
|
||||
|
||||
# Sender is owner of this alias
|
||||
alias.enabled = False
|
||||
db.session.commit()
|
||||
user = alias.user
|
||||
|
||||
enable_alias_url = URL + f"/dashboard/?highlight_alias_id={alias.id}"
|
||||
send_email(
|
||||
envelope.mail_from,
|
||||
f"Alias {alias.email} has been disabled successfully",
|
||||
render(
|
||||
"transactional/unsubscribe-disable-alias.txt",
|
||||
user=user,
|
||||
alias=alias.email,
|
||||
enable_alias_url=enable_alias_url,
|
||||
),
|
||||
render(
|
||||
"transactional/unsubscribe-disable-alias.html",
|
||||
user=user,
|
||||
alias=alias.email,
|
||||
enable_alias_url=enable_alias_url,
|
||||
),
|
||||
)
|
||||
|
||||
return "250 Unsubscribe request accepted"
|
||||
|
||||
|
||||
class MailHandler:
|
||||
async def handle_DATA(self, server, session, envelope):
|
||||
LOG.debug(
|
||||
|
@ -757,6 +810,14 @@ class MailHandler:
|
|||
else:
|
||||
smtp = SMTP(POSTFIX_SERVER, 25)
|
||||
|
||||
# unsubscribe request
|
||||
if UNSUBSCRIBER and envelope.rcpt_tos == [UNSUBSCRIBER]:
|
||||
LOG.d("Handle unsubscribe request from %s", envelope.mail_from)
|
||||
app = new_app()
|
||||
|
||||
with app.app_context():
|
||||
return handle_unsubscribe(envelope)
|
||||
|
||||
# result of all deliveries
|
||||
# each element is a couple of whether the delivery is successful and the smtp status
|
||||
res: [(bool, str)] = []
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
{{ render_text("Hi " + user.name) }}
|
||||
{{ render_text("Your alias <b>"+ alias +"</b> has been disabled successfully.") }}
|
||||
{{ render_text("If this is a mistake, you can re-enable the alias on the dashboard.") }}
|
||||
{{ render_button("Enable Alias", enable_alias_url) }}
|
||||
{{ render_text('Thanks, <br />SimpleLogin Team.') }}
|
||||
{{ raw_url(enable_alias_url) }}
|
||||
{% endblock %}
|
||||
|
12
templates/emails/transactional/unsubscribe-disable-alias.txt
Normal file
12
templates/emails/transactional/unsubscribe-disable-alias.txt
Normal file
|
@ -0,0 +1,12 @@
|
|||
Hi {{user.name}}
|
||||
|
||||
Your alias {{alias}} has been disabled successfully.
|
||||
|
||||
If this is a mistake, you can re-enable the alias on the dashboard via
|
||||
|
||||
{{ enable_alias_url }}
|
||||
|
||||
Please let us know if you have any question.
|
||||
|
||||
Best,
|
||||
SimpleLogin team.
|
Loading…
Reference in a new issue