Spaces:
Sleeping
Sleeping
File size: 5,445 Bytes
45a58f3 df98da1 6044c8f df98da1 b9c7033 df98da1 6044c8f 45a58f3 b9c7033 dc77965 b9c7033 6044c8f b9c7033 675b2c8 b9c7033 06cb529 c701390 675b2c8 06cb529 675b2c8 6044c8f 06cb529 675b2c8 45a58f3 675b2c8 06cb529 675b2c8 06cb529 189dd8c df98da1 6044c8f df98da1 6044c8f df98da1 45a58f3 df98da1 b9c7033 45a58f3 df98da1 b9c7033 45a58f3 b9c7033 df98da1 675b2c8 45a58f3 675b2c8 | 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 | """Email: Mailjet (HTTPS) β Resend β Brevo SMTP (port 2525) β SMTP fallback."""
import os
import smtplib
import base64
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
def _build_body(username: str, reset_url: str) -> str:
return (
f"Hi {username},\n\n"
f"We received a request to reset your YapStation password.\n\n"
f"Open this link (valid for 1 hour):\n{reset_url}\n\n"
f"If you did not request this, ignore this email.\n\n"
f"β YapStation"
)
def _build_msg(mail_from: str, to_email: str, username: str, reset_url: str) -> MIMEMultipart:
msg = MIMEMultipart()
msg["Subject"] = "YapStation β reset your password"
msg["From"] = mail_from
msg["To"] = to_email
msg.attach(MIMEText(_build_body(username, reset_url), "plain", "utf-8"))
return msg
def _send_via_mailjet(to_email: str, username: str, reset_url: str) -> bool:
api_key = os.environ.get("MAILJET_API_KEY", "").strip()
secret_key = os.environ.get("MAILJET_SECRET_KEY", "").strip()
if not api_key or not secret_key:
return False
try:
import httpx
mail_from = os.environ.get("MAIL_FROM", "yapstation.official@gmail.com").strip()
resp = httpx.post(
"https://api.mailjet.com/v3.1/send",
auth=(api_key, secret_key),
json={
"Messages": [{
"From": {"Email": mail_from, "Name": "YapStation"},
"To": [{"Email": to_email}],
"Subject": "YapStation β reset your password",
"TextPart": _build_body(username, reset_url),
}]
},
timeout=15,
)
if resp.status_code == 200:
return True
print(f"[mail] Mailjet error {resp.status_code}: {resp.text}")
return False
except Exception as e:
print(f"[mail] Mailjet failed: {e}")
return False
def _send_via_resend(to_email: str, username: str, reset_url: str) -> bool:
api_key = os.environ.get("RESEND_API_KEY", "").strip()
if not api_key:
return False
try:
import httpx
mail_from = os.environ.get("MAIL_FROM", "YapStation <onboarding@resend.dev>").strip()
resp = httpx.post(
"https://api.resend.com/emails",
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
json={"from": mail_from, "to": [to_email], "subject": "YapStation β reset your password", "text": _build_body(username, reset_url)},
timeout=15,
)
if resp.status_code in (200, 201):
return True
print(f"[mail] Resend error {resp.status_code}: {resp.text}")
return False
except Exception as e:
print(f"[mail] Resend failed: {e}")
return False
def _send_via_brevo(to_email: str, username: str, reset_url: str) -> bool:
smtp_user = os.environ.get("BREVO_SMTP_USER", "").strip().strip('"').strip("'")
smtp_key = os.environ.get("BREVO_API_KEY", "").strip().strip('"').strip("'").replace(" ", "")
if not smtp_user or not smtp_key:
return False
mail_from = os.environ.get("MAIL_FROM", smtp_user).strip()
msg = _build_msg(mail_from, to_email, username, reset_url)
try:
with smtplib.SMTP("smtp-relay.brevo.com", 2525, timeout=30) as smtp:
smtp.ehlo(); smtp.starttls(); smtp.ehlo()
smtp.login(smtp_user, smtp_key)
smtp.sendmail(mail_from, [to_email], msg.as_string())
return True
except Exception as e:
print(f"[mail] Brevo SMTP failed ({type(e).__name__}): {e}")
return False
def _send_via_smtp(to_email: str, username: str, reset_url: str) -> bool:
host = os.environ.get("SMTP_HOST", "").strip()
if not host or not to_email:
return False
port = int(os.environ.get("SMTP_PORT", "587"))
user = os.environ.get("SMTP_USER", "").strip()
password = "".join(os.environ.get("SMTP_PASSWORD", "").split()).strip('"').strip("'")
mail_from = os.environ.get("MAIL_FROM", user or "noreply@localhost").strip()
msg = _build_msg(mail_from, to_email, username, reset_url)
try:
if port == 465:
with smtplib.SMTP_SSL(host, port, timeout=30) as smtp:
if user and password: smtp.login(user, password)
smtp.sendmail(mail_from, [to_email], msg.as_string())
else:
with smtplib.SMTP(host, port, timeout=30) as smtp:
smtp.ehlo(); smtp.starttls(); smtp.ehlo()
if user and password: smtp.login(user, password)
smtp.sendmail(mail_from, [to_email], msg.as_string())
return True
except Exception as e:
print(f"[mail] SMTP send failed ({type(e).__name__}): {e}")
return False
def send_password_reset_email(to_email: str, username: str, reset_url: str) -> bool:
return _send_via_mailjet(to_email, username, reset_url) or _send_via_resend(to_email, username, reset_url) or _send_via_brevo(to_email, username, reset_url) or _send_via_smtp(to_email, username, reset_url)
def smtp_configured() -> bool:
return bool(
os.environ.get("MAILJET_API_KEY", "").strip()
or os.environ.get("RESEND_API_KEY", "").strip()
or os.environ.get("BREVO_SMTP_USER", "").strip()
or os.environ.get("SMTP_HOST", "").strip()
)
|