"""HTML Email Templates for Secuird. This module provides beautifully designed HTML email templates with Secuird branding, responsive design, and consistent styling. """ import os from typing import Optional from flask import current_app PRIMARY_COLOR = "#36b9a6" PRIMARY_DARK = "#2d9a89" TEXT_COLOR = "#1e293b" MUTED_COLOR = "#64748b" BORDER_COLOR = "#e2e8f0" BACKGROUND_COLOR = "#f8fafc" WHITE = "#ffffff" DANGER_COLOR = "#dc2626" WARNING_COLOR = "#f59e0b" SUCCESS_COLOR = "#16a34a" def get_logo_url() -> str: """Get the email logo URL from config or use default inline SVG.""" return current_app.config.get("EMAIL_BRAND_LOGO_URL", "") def get_brand_name() -> str: """Get the brand name from config.""" return current_app.config.get("EMAIL_BRAND_NAME", "Secuird") def get_support_email() -> str: """Get the support email from config.""" return current_app.config.get("EMAIL_SUPPORT_EMAIL", "support@secuird.tech") def get_website_url() -> str: """Get the website URL from config.""" return current_app.config.get("EMAIL_WEBSITE_URL", "https://secuird.tech") def get_app_url() -> str: """Get the app URL from config.""" return current_app.config.get("APP_URL", "https://secuird.tech") def get_inline_logo() -> str: """Returns an inline SVG logo as a data URI for email embedding.""" return ( '' ) def get_base_html( content: str, subject: str, preheader: Optional[str] = None, ) -> str: """Generate the base HTML email template. Args: content: The main content HTML subject: Email subject (used for title and header) preheader: Preview text shown in email clients Returns: Complete HTML email string """ logo = get_inline_logo() brand_name = get_brand_name() support_email = get_support_email() website_url = get_website_url() app_url = get_app_url() current_year = __import__("datetime").datetime.now().year return f'''
|
| {text} |
|
{icon} {text} |
| {label} | {value} |
Hi {user_name},
Thank you for registering with Secuird. Please verify your email address by clicking the button below:
{get_action_button(verify_link, "Verify Email Address")}This link will expire in {expiry_hours} hours. If you didn't create an account, you can safely ignore this email.
{get_alert_box("For security reasons, please don't forward this email to anyone.", "warning", "⚠️")} ''' return get_base_html(content, "Verify your Secuird email address", "Please verify your email address to activate your account") def build_password_reset_html( user_name: str, reset_link: str, expiry_hours: int = 2, ) -> str: """Build password reset email. Args: user_name: Recipient's name or email reset_link: Password reset link URL expiry_hours: Hours until link expires Returns: HTML email string """ content = f'''Hi {user_name},
We received a request to reset your password. Click the button below to create a new one:
{get_action_button(reset_link, "Reset Password", WARNING_COLOR)}This link will expire in {expiry_hours} hours.
{get_alert_box("If you didn't request a password reset, your account is secure. You can safely ignore this email.", "info", "🔒")} ''' return get_base_html(content, "Reset your Secuird password", "Click the button to reset your password") def build_account_activation_html( user_name: str, activation_link: str, ) -> str: """Build account activation email. Args: user_name: Recipient's name or email activation_link: Account activation link URL Returns: HTML email string """ content = f'''Hi {user_name},
Your account has been created but is not yet activated. Click the button below to activate it:
{get_action_button(activation_link, "Activate Account", SUCCESS_COLOR)} {get_alert_box("If you didn't create an account, you can safely ignore this email.", "warning", "⚠️")} ''' return get_base_html(content, "Activate your Secuird account", "Activate your account to get started") def build_mfa_deadline_reminder_html( user_name: str, org_name: str, days_remaining: int, deadline_date: str, mfa_methods: str, setup_link: str, ) -> str: """Build MFA deadline reminder email. Args: user_name: Recipient's name or email org_name: Organization name days_remaining: Days until MFA deadline deadline_date: Formatted deadline date mfa_methods: Required MFA methods setup_link: Link to set up MFA Returns: HTML email string """ urgency = "immediate action" if days_remaining <= 3 else "attention required" content = f'''Dear {user_name},
{get_alert_box(f"Important: You have {days_remaining} days to set up multi-factor authentication for your account with {org_name}.", "warning", "⏰")}To maintain access to your account, please complete the following:
Required MFA Methods:{mfa_methods} Deadline:{deadline_date} |
If you do not set up MFA by the deadline, your account access will be restricted.
If you have questions, please contact your organization administrator.
''' subject = f"Action Required: MFA enrollment deadline in {days_remaining} days" return get_base_html(content, subject, f"MFA enrollment required for {org_name} - {days_remaining} days remaining") def build_mfa_suspension_html( user_name: str, org_name: str, mfa_methods: str, setup_link: str, ) -> str: """Build MFA suspension notification email. Args: user_name: Recipient's name or email org_name: Organization name mfa_methods: Required MFA methods setup_link: Link to set up MFA Returns: HTML email string """ content = f'''Dear {user_name},
{get_alert_box("Your account has been suspended because you did not set up multi-factor authentication within the required timeframe.", "danger", "🚫")}To restore access to your account with {org_name}, please complete the following:
Required MFA Methods:{mfa_methods} How to Restore Access:
|
Need help? Contact your organization administrator.
''' return get_base_html(content, "Account Access Restricted - MFA Enrollment Required", "Your account has been suspended due to missing MFA") def build_org_invite_html( inviter_name: str, org_name: str, invite_link: str, role: str, expiry_days: int = 7, ) -> str: """Build organization invite email. Args: inviter_name: Name of person who sent the invite org_name: Organization name invite_link: Invitation acceptance link role: Role the invitee will have expiry_days: Days until invite expires Returns: HTML email string """ content = f'''You've been invited by {inviter_name} to join {org_name} on Secuird.
Invitation Details:Organization: {org_name} Role: {role} This invitation expires in {expiry_days} days |
If you did not expect this invitation, you can safely ignore this email.
''' return get_base_html(content, f"You're invited to join {org_name} on Secuird", f"You've been invited to join {org_name}") def build_email_verification_resend_html( user_name: str, verify_link: str, expiry_hours: int = 24, ) -> str: """Build email verification resend email. Args: user_name: Recipient's name or email verify_link: Verification link URL expiry_hours: Hours until link expires Returns: HTML email string """ content = f'''Hi {user_name},
Please verify your email address by clicking the button below:
{get_action_button(verify_link, "Verify Email Address")}This link will expire in {expiry_hours} hours.
{get_alert_box("If you didn't request this, you can safely ignore this email.", "info", "🔒")} ''' return get_base_html(content, "Verify your Secuird email address", "Please verify your email address") def build_contact_enquiry_html( enquiry_type: str, submitter_email: str, name: Optional[str], company: Optional[str], interest_area: Optional[str], message: Optional[str], ) -> str: """Build a contact enquiry notification email. Args: enquiry_type: One of demo_request, sales_enquiry, general, support submitter_email: Email address of the person submitting the enquiry name: Full name of the submitter (optional) company: Company name (optional) interest_area: Area of interest (optional) message: Free-text message (optional) Returns: HTML email string """ # Map enquiry types to display labels and colors type_labels = { "demo_request": ("Demo Request", "info"), "sales_enquiry": ("Sales Enquiry", "success"), "general": ("General Enquiry", "info"), "support": ("Support Request", "warning"), } type_label, alert_type = type_labels.get(enquiry_type, ("Enquiry", "info")) name_display = name if name else "Not provided" company_display = company if company else "Not provided" interest_display = interest_area if interest_area else "Not provided" message_display = message if message else "No message provided" # Build details table details_rows = f""" {get_detail_row("Enquiry Type", type_label)} {get_detail_row("Submitter Email", submitter_email)} {get_detail_row("Name", name_display)} {get_detail_row("Company", company_display)} {get_detail_row("Interest Area", interest_display)} """ content = f'''A new {type_label.lower()} has been submitted through the Secuird website.
{get_alert_box(f"Enquiry type: {type_label}", alert_type, "📬")}
Enquiry Details |
{message_display}
''' return get_base_html(content, f"Secuird Website: {type_label}", f"New {type_label} from {submitter_email}") def build_invite_accepted_html( inviter_name: str, member_name: str, member_email: str, org_name: str, role: str, org_link: Optional[str] = None, ) -> str: """Build invite accepted notification email. Args: inviter_name: Name of the person who sent the invite member_name: Name of the person who accepted member_email: Email of the person who accepted org_name: Organization name role: Role assigned to the member org_link: Optional link to view the organization Returns: HTML email string """ content = f'''{member_name} has accepted your invitation to join {org_name} on Secuird.
{get_alert_box(f"{member_name} ({member_email}) has joined {org_name}", "success", "✅")}
Membership Details |