diff --git a/bp/auth/services/auth_operations.py b/bp/auth/services/auth_operations.py
index a0d0d9c..d9964a4 100644
--- a/bp/auth/services/auth_operations.py
+++ b/bp/auth/services/auth_operations.py
@@ -5,7 +5,7 @@ import secrets
from datetime import datetime, timedelta, timezone
from typing import Optional, Tuple
-from quart import current_app, request, g
+from quart import current_app, render_template, request, g
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload
@@ -45,16 +45,12 @@ async def send_magic_email(to_email: str, link_url: str) -> None:
password = os.getenv("SMTP_PASS")
mail_from = os.getenv("MAIL_FROM") or "no-reply@example.com"
- subject = "Your sign-in link"
- body = f"""Hello,
+ site_name = config().get("title", "Rose Ash")
+ subject = f"Your sign-in link — {site_name}"
-Click this link to sign in:
-{link_url}
-
-This link will expire in 15 minutes.
-
-If you did not request this, you can ignore this email.
-"""
+ tpl_vars = dict(site_name=site_name, link_url=link_url)
+ text_body = await render_template("_email/magic_link.txt", **tpl_vars)
+ html_body = await render_template("_email/magic_link.html", **tpl_vars)
if not host or not username or not password:
# Fallback: log to console
@@ -74,7 +70,8 @@ If you did not request this, you can ignore this email.
msg["From"] = mail_from
msg["To"] = to_email
msg["Subject"] = subject
- msg.set_content(body)
+ msg.set_content(text_body)
+ msg.add_alternative(html_body, subtype="html")
is_secure = port == 465 # implicit TLS if true
if is_secure:
diff --git a/templates/_email/magic_link.html b/templates/_email/magic_link.html
new file mode 100644
index 0000000..3c1eac6
--- /dev/null
+++ b/templates/_email/magic_link.html
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+ {{ site_name }}
+ Sign in to your account
+
+ Click the button below to sign in. This link will expire in 15 minutes.
+
+
+ Or copy and paste this link into your browser:
+
+ {{ link_url }}
+
+
+
+ If you did not request this email, you can safely ignore it.
+
+ |
+
+ |
+
+
+
diff --git a/templates/_email/magic_link.txt b/templates/_email/magic_link.txt
new file mode 100644
index 0000000..28a2efb
--- /dev/null
+++ b/templates/_email/magic_link.txt
@@ -0,0 +1,8 @@
+Hello,
+
+Click this link to sign in:
+{{ link_url }}
+
+This link will expire in 15 minutes.
+
+If you did not request this, you can ignore this email.