Spaces:
Running
Running
File size: 7,413 Bytes
b5cb5bb | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | import html
from dataclasses import dataclass
from urllib.parse import urlparse
WELCOME_SUBJECT = "Welcome to MathPulse AI - Your Account Details"
ACCENT_COLOR = "#9956DE"
@dataclass
class WelcomeCredentialsEmailContext:
recipient_name: str
login_email: str
temporary_password: str
role: str
login_url: str
brand_avatar_url: str = ""
recipient_avatar_url: str = ""
def _normalize_display_name(name: str) -> str:
cleaned = (name or "").strip()
return cleaned or "Learner"
def _normalize_http_url(url: str) -> str:
candidate = (url or "").strip()
if not candidate:
return ""
parsed = urlparse(candidate)
if parsed.scheme.lower() not in {"http", "https"}:
return ""
if not parsed.netloc:
return ""
return candidate
def build_welcome_credentials_email(context: WelcomeCredentialsEmailContext) -> dict:
recipient_name = _normalize_display_name(context.recipient_name)
login_email = (context.login_email or "").strip()
temporary_password = (context.temporary_password or "").strip()
role = (context.role or "").strip() or "User"
login_url = _normalize_http_url(context.login_url) or "https://mathpulse.ai"
brand_avatar_url = _normalize_http_url(context.brand_avatar_url)
recipient_avatar_url = _normalize_http_url(context.recipient_avatar_url)
escaped_name = html.escape(recipient_name)
escaped_email = html.escape(login_email)
escaped_password = html.escape(temporary_password)
escaped_role = html.escape(role)
escaped_url = html.escape(login_url, quote=True)
escaped_brand_avatar_url = html.escape(brand_avatar_url, quote=True)
escaped_recipient_avatar_url = html.escape(recipient_avatar_url, quote=True)
recipient_initial = html.escape((recipient_name[:1] or "U").upper())
if escaped_brand_avatar_url:
brand_avatar_markup = (
f'<img src="{escaped_brand_avatar_url}" width="46" height="46" alt="MathPulse avatar" '
'style="display:block;width:46px;height:46px;border-radius:50%;background:#ffffff;border:2px solid rgba(255,255,255,0.65);" />'
)
else:
brand_avatar_markup = (
'<div style="width:46px;height:46px;border-radius:50%;background:#1b1331;color:#f5ebff;'
'font-size:16px;font-weight:800;line-height:46px;text-align:center;border:2px solid rgba(255,255,255,0.4);">MP</div>'
)
if escaped_recipient_avatar_url:
recipient_avatar_markup = (
f'<img src="{escaped_recipient_avatar_url}" width="54" height="54" alt="Learner avatar" '
'style="display:block;width:54px;height:54px;border-radius:50%;background:#1f2937;border:1px solid #49537a;" />'
)
else:
recipient_avatar_markup = (
'<div style="width:54px;height:54px;border-radius:50%;background:#233e74;color:#f8fafc;'
f'font-size:22px;font-weight:700;line-height:54px;text-align:center;">{recipient_initial}</div>'
)
html_content = f"""
<!DOCTYPE html>
<html lang=\"en\">
<head>
<meta charset=\"UTF-8\" />
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />
<title>{WELCOME_SUBJECT}</title>
</head>
<body style=\"margin:0;padding:0;background:#0f1220;font-family:Segoe UI,Arial,sans-serif;color:#e5e7eb;\">
<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"padding:24px 12px;background:#0f1220;\">
<tr>
<td align=\"center\">
<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"max-width:640px;background:#181d2f;border-radius:18px;overflow:hidden;border:1px solid #343e62;\">
<tr>
<td style=\"background:{ACCENT_COLOR};padding:14px 22px;\">
<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\">
<tr>
<td width=\"52\" valign=\"middle\" style=\"width:52px;\">{brand_avatar_markup}</td>
<td valign=\"middle\" style=\"padding-left:10px;\">
<p style=\"margin:0;color:#1f1238;font-size:20px;font-weight:800;line-height:1.15;\">MathPulse AI</p>
<p style=\"margin:2px 0 0 0;color:#2f1d50;font-size:12px;font-weight:600;line-height:1.4;\">Learning Platform Account Access</p>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style=\"padding:24px;\">
<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"margin:0 0 14px 0;\">
<tr>
<td width=\"62\" valign=\"top\" style=\"width:62px;padding-right:12px;\">{recipient_avatar_markup}</td>
<td valign=\"top\">
<p style=\"margin:0 0 8px 0;font-size:16px;color:#f3f4f6;\">Hello {escaped_name},</p>
<p style=\"margin:0;line-height:1.6;color:#d6daeb;\">Welcome to MathPulse AI. Your account has been created by your administrator. Use the credentials below to sign in and begin your learning journey.</p>
</td>
</tr>
</table>
<table role=\"presentation\" width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"background:#20263b;border:1px solid #445077;border-radius:12px;padding:16px;\">
<tr><td style=\"padding:4px 0;font-size:14px;color:#e5e7eb;\"><strong>Email:</strong> <span style=\"color:#93c5fd;\">{escaped_email}</span></td></tr>
<tr><td style=\"padding:4px 0;font-size:14px;color:#e5e7eb;\"><strong>Temporary Password:</strong> {escaped_password}</td></tr>
<tr><td style=\"padding:4px 0;font-size:14px;color:#e5e7eb;\"><strong>Role:</strong> {escaped_role}</td></tr>
</table>
<table role=\"presentation\" cellspacing=\"0\" cellpadding=\"0\" style=\"margin:20px 0 14px 0;\">
<tr>
<td align=\"center\" bgcolor=\"{ACCENT_COLOR}\" style=\"border-radius:10px;\">
<a href=\"{escaped_url}\" style=\"display:inline-block;padding:12px 20px;color:#1f1238;text-decoration:none;font-weight:700;font-size:14px;\">Log in to MathPulse</a>
</td>
</tr>
</table>
<p style=\"margin:0 0 8px 0;font-size:13px;line-height:1.5;color:#c7d2fe;\">Security note: Please change your password after your first login.</p>
<p style=\"margin:0;font-size:12px;line-height:1.5;color:#a8b3d1;\">If you did not expect this email, please contact your administrator.</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
""".strip()
text_content = (
"MathPulse AI\n\n"
f"Hello {recipient_name},\n\n"
"Welcome to MathPulse AI. Your account has been created by your administrator.\n\n"
"Account details:\n"
f"- Email: {login_email}\n"
f"- Temporary Password: {temporary_password}\n"
f"- Role: {role}\n\n"
f"Log in here: {login_url}\n\n"
"Security note: Please change your password after your first login.\n\n"
"If you did not expect this email, please contact your administrator.\n"
)
return {
"subject": WELCOME_SUBJECT,
"html": html_content,
"text": text_content,
}
|