154 lines
6.8 KiB
Python
154 lines
6.8 KiB
Python
import logging
|
|
import resend
|
|
from config import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def send_email(to: str, subject: str, html: str) -> None:
|
|
"""Send a transactional email via Resend. Logs errors but does not raise."""
|
|
try:
|
|
resend.api_key = settings.resend_api_key
|
|
resend.Emails.send({
|
|
"from": settings.email_from,
|
|
"to": to,
|
|
"subject": subject,
|
|
"html": html,
|
|
})
|
|
logger.info("Email sent to %s — subject: %s", to, subject)
|
|
except Exception as exc:
|
|
logger.error("Failed to send email to %s: %s", to, exc)
|
|
raise
|
|
|
|
|
|
def send_device_assignment_invite(
|
|
customer_email: str,
|
|
serial_number: str,
|
|
device_name: str,
|
|
customer_name: str | None = None,
|
|
) -> None:
|
|
"""Notify a customer that a Bell Systems device has been assigned and shipped to them."""
|
|
greeting = f"Dear {customer_name}," if customer_name else "Dear Customer,"
|
|
html = f"""
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
|
|
<body style="margin:0; padding:0; background-color:#f4f4f7; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;">
|
|
<table width="100%" cellpadding="0" cellspacing="0" style="background-color:#f4f4f7; padding: 40px 0;">
|
|
<tr>
|
|
<td align="center">
|
|
<table width="600" cellpadding="0" cellspacing="0" style="background-color:#ffffff; border-radius:8px; overflow:hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.08); max-width:600px; width:100%;">
|
|
|
|
<!-- Header -->
|
|
<tr>
|
|
<td style="background-color:#0f172a; padding: 32px 40px; text-align:center;">
|
|
<h1 style="color:#ffffff; margin:0; font-size:22px; font-weight:700; letter-spacing:1px;">BELLSYSTEMS</h1>
|
|
<p style="color:#94a3b8; margin:6px 0 0; font-size:13px; letter-spacing:2px; text-transform:uppercase;">Device Shipment Confirmation</p>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- Body -->
|
|
<tr>
|
|
<td style="padding: 40px 40px 32px;">
|
|
<p style="margin:0 0 20px; font-size:16px; color:#1e293b;">{greeting}</p>
|
|
|
|
<p style="margin:0 0 16px; font-size:15px; color:#334155; line-height:1.7;">
|
|
Your <strong>Bell Systems {device_name}</strong> device has been successfully manufactured and shipped.
|
|
We are delighted to have it on its way to you!
|
|
</p>
|
|
|
|
<p style="margin:0 0 24px; font-size:15px; color:#334155; line-height:1.7;">
|
|
To get started, download our controller application from the Google Play Store and follow the in-app setup instructions.
|
|
</p>
|
|
|
|
<!-- CTA Button -->
|
|
<table cellpadding="0" cellspacing="0" width="100%" style="margin: 28px 0;">
|
|
<tr>
|
|
<td align="center">
|
|
<a href="https://play.google.com/store/apps/details?id=com.bellsystems.vesper"
|
|
style="display:inline-block; background-color:#0f172a; color:#ffffff; text-decoration:none;
|
|
padding:14px 32px; border-radius:6px; font-size:15px; font-weight:600; letter-spacing:0.5px;">
|
|
Download on Google Play
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- Device info card -->
|
|
<table width="100%" cellpadding="0" cellspacing="0" style="background:#f8fafc; border:1px solid #e2e8f0; border-radius:6px; margin-bottom:28px;">
|
|
<tr>
|
|
<td style="padding:16px 20px; border-bottom:1px solid #e2e8f0;">
|
|
<span style="font-size:12px; color:#64748b; text-transform:uppercase; letter-spacing:1px; font-weight:600;">Device</span><br>
|
|
<span style="font-size:15px; color:#0f172a; font-weight:600;">Bell Systems {device_name}</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding:16px 20px;">
|
|
<span style="font-size:12px; color:#64748b; text-transform:uppercase; letter-spacing:1px; font-weight:600;">Serial Number</span><br>
|
|
<code style="font-size:14px; color:#0f172a; background:#e2e8f0; padding:3px 8px; border-radius:4px; font-family:monospace;">{serial_number}</code>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<p style="margin:0; font-size:15px; color:#334155; line-height:1.7;">
|
|
Thank you very much. We greatly appreciate your choice in our products.
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- Footer -->
|
|
<tr>
|
|
<td style="background-color:#f8fafc; border-top:1px solid #e2e8f0; padding:24px 40px; text-align:center;">
|
|
<p style="margin:0 0 4px; font-size:14px; color:#0f172a; font-weight:700;">BellSystems.gr</p>
|
|
<p style="margin:0; font-size:12px; color:#94a3b8;">
|
|
If you did not expect this email, please contact us at
|
|
<a href="mailto:support@bellsystems.gr" style="color:#64748b;">support@bellsystems.gr</a>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>
|
|
"""
|
|
send_email(
|
|
to=customer_email,
|
|
subject=f"Your Bell Systems {device_name} is on its way! 🎉",
|
|
html=html,
|
|
)
|
|
|
|
|
|
def send_device_provisioned_alert(
|
|
admin_email: str,
|
|
serial_number: str,
|
|
hw_type: str,
|
|
) -> None:
|
|
"""Internal alert sent to an admin when a device reaches provisioned status."""
|
|
html = f"""
|
|
<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto;">
|
|
<h2 style="color: #111827;">Device Provisioned</h2>
|
|
<p>A Vesper device has successfully provisioned and is ready to ship.</p>
|
|
<table style="border-collapse: collapse; width: 100%; margin-top: 16px;">
|
|
<tr>
|
|
<td style="padding: 6px 12px; font-weight: bold; background: #f9fafb;">Serial Number</td>
|
|
<td style="padding: 6px 12px; font-family: monospace;">{serial_number}</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 6px 12px; font-weight: bold; background: #f9fafb;">Board Type</td>
|
|
<td style="padding: 6px 12px;">{hw_type.upper()}</td>
|
|
</tr>
|
|
</table>
|
|
<p style="margin-top: 24px;">
|
|
<a href="#" style="color: #2563eb;">View in Admin Console</a>
|
|
</p>
|
|
</div>
|
|
"""
|
|
send_email(
|
|
to=admin_email,
|
|
subject=f"[Vesper] Device provisioned — {serial_number}",
|
|
html=html,
|
|
)
|