| import os |
| import smtplib |
| from email.mime.text import MIMEText |
| from email.mime.multipart import MIMEMultipart |
| from email.mime.image import MIMEImage |
| from dotenv import load_dotenv |
| import asyncio |
| from utils.url_utils import get_frontend_url |
| from utils.config_loader import get_setting |
|
|
| load_dotenv() |
|
|
| |
|
|
|
|
| |
| EMAIL_BASE_TEMPLATE = """ |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <style> |
| body {{ |
| margin: 0; |
| padding: 0; |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| }} |
| .email-wrapper {{ |
| max-width: 600px; |
| margin: 40px auto; |
| background: #ffffff; |
| border-radius: 20px; |
| overflow: hidden; |
| box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); |
| }} |
| .email-header {{ |
| background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%); |
| padding: 40px 30px; |
| text-align: center; |
| position: relative; |
| overflow: hidden; |
| }} |
| .email-header::before {{ |
| content: ''; |
| position: absolute; |
| top: -50%; |
| left: -50%; |
| width: 200%; |
| height: 200%; |
| background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%); |
| animation: pulse 4s ease-in-out infinite; |
| }} |
| @keyframes pulse {{ |
| 0%, 100% {{ transform: scale(1); opacity: 0.5; }} |
| 50% {{ transform: scale(1.1); opacity: 0.8; }} |
| }} |
| .logo {{ |
| width: 120px; /* Increased size */ |
| height: 120px; /* Increased size */ |
| /* Removed background and box-shadow as image will provide styling */ |
| border-radius: 15px; |
| display: inline-flex; |
| align-items: center; |
| justify-content: center; |
| margin-bottom: 15px; |
| position: relative; |
| z-index: 1; |
| }} |
| .logo img {{ |
| width: 100%; |
| height: 100%; |
| object-fit: contain; |
| border-radius: 15px; |
| }} |
| .brand-name {{ |
| color: white; |
| font-size: 28px; |
| font-weight: bold; |
| margin: 0; |
| position: relative; |
| z-index: 1; |
| }} |
| .email-body {{ |
| padding: 40px 30px; |
| color: #333333; |
| line-height: 1.8; |
| }} |
| .greeting {{ |
| font-size: 24px; |
| font-weight: bold; |
| color: #1e293b; |
| margin-bottom: 20px; |
| }} |
| .content {{ |
| font-size: 16px; |
| color: #475569; |
| margin-bottom: 25px; |
| }} |
| .highlight {{ |
| color: #06b6d4; |
| font-weight: 600; |
| }} |
| .button-container {{ |
| text-align: center; |
| margin: 35px 0; |
| }} |
| .button {{ |
| display: inline-block; |
| padding: 16px 40px; |
| background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%); |
| color: white; |
| text-decoration: none; |
| border-radius: 12px; |
| font-weight: 600; |
| font-size: 16px; |
| box-shadow: 0 10px 30px rgba(6, 182, 212, 0.4); |
| transition: transform 0.3s ease; |
| }} |
| .info-box {{ |
| background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); |
| border-left: 4px solid #06b6d4; |
| padding: 20px; |
| border-radius: 12px; |
| margin: 25px 0; |
| }} |
| .info-box-title {{ |
| font-weight: 600; |
| color: #0c4a6e; |
| margin-bottom: 10px; |
| font-size: 18px; |
| }} |
| .info-item {{ |
| margin: 8px 0; |
| color: #475569; |
| }} |
| .alert-box {{ |
| background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%); |
| border-left: 4px solid #ef4444; |
| padding: 20px; |
| border-radius: 12px; |
| margin: 25px 0; |
| }} |
| .alert-box-title {{ |
| font-weight: 600; |
| color: #991b1b; |
| margin-bottom: 10px; |
| font-size: 18px; |
| }} |
| .success-box {{ |
| background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); |
| border-left: 4px solid #22c55e; |
| padding: 20px; |
| border-radius: 12px; |
| margin: 25px 0; |
| }} |
| .success-box-title {{ |
| font-weight: 600; |
| color: #166534; |
| margin-bottom: 10px; |
| font-size: 18px; |
| }} |
| .footer {{ |
| background: #f8fafc; |
| padding: 30px; |
| text-align: center; |
| border-top: 1px solid #e2e8f0; |
| }} |
| .footer-text {{ |
| color: #64748b; |
| font-size: 14px; |
| margin: 5px 0; |
| }} |
| .social-links {{ |
| margin: 20px 0; |
| }} |
| .social-link {{ |
| display: inline-block; |
| width: 40px; |
| height: 40px; |
| background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%); |
| border-radius: 50%; |
| margin: 0 5px; |
| line-height: 40px; |
| color: white; |
| text-decoration: none; |
| font-weight: bold; |
| }} |
| @media only screen and (max-width: 600px) {{ |
| .email-wrapper {{ |
| margin: 20px; |
| }} |
| .email-body {{ |
| padding: 30px 20px; |
| }} |
| }} |
| </style> |
| </head> |
| <body> |
| <div class="email-wrapper"> |
| <div class="email-header"> |
| <div class="logo"> |
| <img src="cid:mediflow-logo" alt="MediSync Logo" style="width: 100%; height: 100%; object-fit: contain; border-radius: 15px;"> |
| </div> |
| <h1 class="brand-name">MediSync</h1> |
| </div> |
| <div class="email-body"> |
| {content} |
| </div> |
| <div class="footer"> |
| <div class="social-links"> |
| <a href="#" class="social-link">f</a> |
| <a href="#" class="social-link">t</a> |
| <a href="#" class="social-link">in</a> |
| </div> |
| <p class="footer-text">Β© 2025 MediSync. All rights reserved.</p> |
| <p class="footer-text">AI-Powered Medicine Dispenser System</p> |
| <p class="footer-text" style="margin-top: 15px;"> |
| <a href="#" style="color: #06b6d4; text-decoration: none;">Privacy Policy</a> | |
| <a href="#" style="color: #06b6d4; text-decoration: none;">Terms of Service</a> |
| </p> |
| </div> |
| </div> |
| </body> |
| </html> |
| """ |
|
|
| |
| ACCOUNT_VERIFICATION_EMAIL_SUBJECT = "Verify your account - MediSync" |
| ACCOUNT_VERIFICATION_EMAIL_CONTENT = """ |
| <p class="greeting">Welcome, {full_name}! π</p> |
| <p class="content"> |
| Thank you for registering with <span class="highlight">MediSync</span>, your AI-Powered Medicine Dispenser System. |
| </p> |
| <p class="content"> |
| To get started and access all the amazing features, please verify your email address by clicking the button below: |
| </p> |
| <div class="button-container"> |
| <a href="{verification_link}" class="button" style="color: #ffffff; text-decoration: none; display: inline-block; padding: 16px 40px; background: linear-gradient(135deg, #06b6d4 0%, #3b82f6 100%); border-radius: 12px; font-weight: 600; font-size: 16px; box-shadow: 0 10px 30px rgba(6, 182, 212, 0.4); transition: transform 0.3s ease;">β Verify Email Address</a> |
| </div> |
| <p class="content" style="font-size: 14px; color: #64748b; margin-top: 20px;"> |
| If the button doesn't work, copy and paste this link into your browser: |
| </p> |
| <p class="content" style="word-break: break-all; background: #f8fafc; padding: 15px; border-radius: 8px; border: 1px solid #e2e8f0; font-family: 'Courier New', monospace; font-size: 14px; color: #06b6d4;"> |
| {verification_link} |
| </p> |
| <p class="content" style="font-size: 14px; color: #64748b;"> |
| If you didn't create this account, you can safely ignore this email. |
| </p> |
| <div class="info-box"> |
| <div class="info-box-title">π Security Tip</div> |
| <p style="margin: 5px 0; color: #475569; font-size: 14px;"> |
| Never share your verification link with anyone. MediSync will never ask for your password via email. |
| </p> |
| </div> |
| """ |
|
|
| |
| MEDICINE_ADDED_EMAIL_SUBJECT = "β Medicine Added to Your Schedule" |
| MEDICINE_ADDED_EMAIL_CONTENT = """ |
| <p class="greeting">Hello, {full_name}! π</p> |
| <p class="content"> |
| Great news! Your medicine has been successfully added to your schedule. |
| </p> |
| <div class="success-box"> |
| <div class="success-box-title">π Medicine Details</div> |
| <div class="info-item">π <strong>Medicine:</strong> {medicine_name}</div> |
| <div class="info-item">π <strong>Dosage:</strong> {dosage}</div> |
| <div class="info-item">β° <strong>Scheduled Time:</strong> {time}</div> |
| </div> |
| <p class="content"> |
| You will receive reminders before each scheduled dose. Stay on track with your health goals! π― |
| </p> |
| <div class="button-container"> |
| <a href="{frontend_url}/dashboard" class="button">View Full Schedule</a> |
| </div> |
| """ |
|
|
| |
| MEDICINE_REMINDER_EMAIL_SUBJECT = "β° Medicine Reminder - Time to Take Your Dose" |
| MEDICINE_REMINDER_EMAIL_CONTENT = """ |
| <p class="greeting">Reminder for {full_name} β°</p> |
| <p class="content"> |
| It's time to take your medicine! Don't forget your health routine. |
| </p> |
| <div class="info-box"> |
| <div class="info-box-title">π Dose Information</div> |
| <div class="info-item">π <strong>Medicine:</strong> {medicine_name}</div> |
| <div class="info-item">π <strong>Dosage:</strong> {dosage}</div> |
| <div class="info-item">β° <strong>Time:</strong> {time}</div> |
| </div> |
| <p class="content"> |
| Please take your medicine as prescribed. Your health is our priority! π |
| </p> |
| <div class="button-container"> |
| <a href="{frontend_url}/dashboard" class="button">Mark as Taken</a> |
| </div> |
| <p class="content" style="font-size: 14px; color: #64748b; text-align: center;"> |
| π‘ Tip: Set up your dispenser for automatic dispensing to never miss a dose! |
| </p> |
| """ |
|
|
| |
| MEDICINE_MISSED_EMAIL_SUBJECT = "β οΈ ALERT: Missed Medicine Notification" |
| MEDICINE_MISSED_EMAIL_CONTENT = """ |
| <p class="greeting">Important Alert, {full_name} β οΈ</p> |
| <div class="alert-box"> |
| <div class="alert-box-title">β οΈ Missed Dose Alert</div> |
| <p style="margin: 10px 0; color: #475569;"> |
| You missed your scheduled medicine dose. Please take it as soon as possible. |
| </p> |
| <div class="info-item">π <strong>Medicine:</strong> {medicine_name}</div> |
| <div class="info-item">π <strong>Dosage:</strong> {dosage}</div> |
| <div class="info-item">β° <strong>Scheduled Time:</strong> {time}</div> |
| </div> |
| <p class="content"> |
| If you have any concerns or questions about your medication schedule, please contact your healthcare provider immediately. |
| </p> |
| <div class="button-container"> |
| <a href="{frontend_url}/dashboard" class="button">View Schedule</a> |
| </div> |
| <div class="info-box"> |
| <div class="info-box-title">π Need Help?</div> |
| <p style="margin: 5px 0; color: #475569; font-size: 14px;"> |
| Contact your doctor or our support team if you need assistance with your medication schedule. |
| </p> |
| </div> |
| """ |
|
|
| |
| MEDICINE_UPDATED_EMAIL_SUBJECT = "π Medicine Schedule Updated" |
| MEDICINE_UPDATED_EMAIL_CONTENT = """ |
| <p class="greeting">Update Notification, {full_name} π</p> |
| <p class="content"> |
| Your medicine schedule has been updated successfully. |
| </p> |
| <div class="info-box"> |
| <div class="info-box-title">π Updated Medicine Details</div> |
| <div class="info-item">π <strong>Medicine:</strong> {medicine_name}</div> |
| <div class="info-item">π <strong>Dosage:</strong> {dosage}</div> |
| <div class="info-item">β° <strong>New Time:</strong> {time}</div> |
| </div> |
| <p class="content"> |
| If you didn't request this change, please contact our support team immediately for assistance. |
| </p> |
| <div class="button-container"> |
| <a href="{frontend_url}/dashboard" class="button">Review Changes</a> |
| </div> |
| <div class="alert-box"> |
| <div class="alert-box-title">π Security Notice</div> |
| <p style="margin: 5px 0; color: #475569; font-size: 14px;"> |
| If this update was unauthorized, please contact support immediately at support@MediSync.com |
| </p> |
| </div> |
| """ |
|
|
| |
| PASSWORD_RESET_EMAIL_SUBJECT = "π Reset Your Password - MediSync" |
| PASSWORD_RESET_EMAIL_CONTENT = """ |
| <p class="greeting">Password Reset Request, {full_name} π</p> |
| <p class="content"> |
| We received a request to reset your password for your MediSync account. |
| </p> |
| <p class="content"> |
| Click the button below to set a new password: |
| </p> |
| <div class="button-container"> |
| <a href="{reset_link}" class="button">π Reset Password</a> |
| </div> |
| <p class="content" style="font-size: 14px; color: #64748b;"> |
| If you didn't request a password reset, you can safely ignore this email. Your password will remain unchanged. |
| </p> |
| <div class="alert-box"> |
| <div class="alert-box-title">β±οΈ Link Expires Soon</div> |
| <p style="margin: 5px 0; color: #475569; font-size: 14px;"> |
| This password reset link will expire in 1 hour for security reasons. |
| </p> |
| </div> |
| """ |
|
|
| |
| PREORDER_CONFIRMATION_EMAIL_SUBJECT = "π Pre-order Confirmed - MediSync" |
| PREORDER_CONFIRMATION_EMAIL_CONTENT = """ |
| <p class="greeting">Thank You, {full_name}! π</p> |
| <p class="content"> |
| We've received your pre-order request for the MediSync AI-Powered Medicine Dispenser! |
| </p> |
| <div class="success-box"> |
| <div class="success-box-title">β What Happens Next?</div> |
| <p style="margin: 10px 0; color: #475569;"> |
| Our team will review your request and contact you within 24-48 hours with next steps. |
| </p> |
| </div> |
| <p class="content"> |
| You're one step closer to revolutionizing your medication management! π |
| </p> |
| <div class="info-box"> |
| <div class="info-box-title">π¦ Product Features</div> |
| <div class="info-item">β Automated dispensing with smart scheduling</div> |
| <div class="info-item">β AI health assistant for medication questions</div> |
| <div class="info-item">β Multi-slot system for up to 8 medications</div> |
| <div class="info-item">β Smart reminders via SMS & Email</div> |
| </div> |
| <p class="content" style="font-size: 14px; color: #64748b;"> |
| Have questions? Feel free to reply to this email anytime! |
| </p> |
| """ |
|
|
| |
| PREORDER_NOTIFICATION_OWNER_SUBJECT = "π New Pre-order Received" |
| PREORDER_NOTIFICATION_OWNER_CONTENT = """ |
| <p class="greeting">New Pre-order Alert! π―</p> |
| <p class="content"> |
| A new customer has submitted a pre-order request for MediSync. |
| </p> |
| <div class="info-box"> |
| <div class="info-box-title">π€ Customer Information</div> |
| <div class="info-item">π€ <strong>Name:</strong> {name}</div> |
| <div class="info-item">π <strong>Phone:</strong> {phone}</div> |
| <div class="info-item">π§ <strong>Email:</strong> {gmail}</div> |
| <div class="info-item">π¬ <strong>Message:</strong> {message}</div> |
| </div> |
| <div class="button-container"> |
| <a href="{frontend_url}/admin/preorders" class="button">View in Dashboard</a> |
| </div> |
| <p class="content" style="font-size: 14px; color: #64748b;"> |
| Please follow up with the customer within 24-48 hours. |
| </p> |
| """ |
|
|
| |
| CONTACT_CONFIRMATION_EMAIL_SUBJECT = "β We've Received Your Message - MediSync" |
| CONTACT_CONFIRMATION_EMAIL_CONTENT = """ |
| <p class="greeting">Thank You, {name}! π¬</p> |
| <p class="content"> |
| We've received your message and appreciate you reaching out to MediSync. |
| </p> |
| <div class="info-box"> |
| <div class="info-box-title">π Message Details</div> |
| <div class="info-item">π§ <strong>Subject:</strong> {subject}</div> |
| <div class="info-item">π¬ <strong>Your Message:</strong> {message}</div> |
| </div> |
| <p class="content"> |
| Our team will review your inquiry and get back to you within 24-48 hours. |
| </p> |
| <div class="success-box"> |
| <div class="success-box-title">β±οΈ Response Time</div> |
| <p style="margin: 10px 0; color: #166534;"> |
| We typically respond to all inquiries within 1-2 business days. |
| </p> |
| </div> |
| <p class="content" style="font-size: 14px; color: #64748b;"> |
| If you have any urgent matters, please call us at +1 (234) 567-8900. |
| </p> |
| """ |
|
|
| |
| CONTACT_NOTIFICATION_OWNER_SUBJECT = "π¬ New Contact Form Submission" |
| CONTACT_NOTIFICATION_OWNER_CONTENT = """ |
| <p class="greeting">New Contact Form Submission! π¬</p> |
| <p class="content"> |
| A visitor has submitted a contact form on the MediSync website. |
| </p> |
| <div class="info-box"> |
| <div class="info-box-title">π€ Contact Information</div> |
| <div class="info-item">π€ <strong>Name:</strong> {name}</div> |
| <div class="info-item">π§ <strong>Email:</strong> {email}</div> |
| <div class="info-item">π <strong>Subject:</strong> {subject}</div> |
| <div class="info-item">π¬ <strong>Message:</strong> {message}</div> |
| </div> |
| <div class="button-container"> |
| <a href="{frontend_url}/admin/messages" class="button">View in Dashboard</a> |
| </div> |
| <p class="content" style="font-size: 14px; color: #64748b;"> |
| Please respond to this inquiry within 24-48 hours. |
| </p> |
| """ |
|
|
| def _send_email(to_email: str, subject: str, html: str): |
| GMAIL_USER = get_setting("GMAIL_USER") |
| GMAIL_PASS = get_setting("GMAIL_PASS") |
|
|
| if not GMAIL_USER or not GMAIL_PASS: |
| print("Gmail credentials not set.") |
| |
| |
| |
| return |
|
|
| |
| msg = MIMEMultipart("related") |
| msg["Subject"] = subject |
| msg["From"] = GMAIL_USER |
| msg["To"] = to_email |
|
|
| |
| msg.attach(MIMEText(html, "html")) |
|
|
| |
| image_path = "mediflow-logo-trans.png" |
| try: |
| with open(image_path, "rb") as img_file: |
| img_data = img_file.read() |
| img = MIMEImage(img_data, name=os.path.basename(image_path)) |
| img.add_header("Content-ID", "<mediflow-logo>") |
| msg.attach(img) |
| except FileNotFoundError: |
| print(f"Warning: Logo image not found at {image_path}. Email will be sent without logo.") |
| except Exception as e: |
| print(f"Error embedding logo image: {e}") |
|
|
| try: |
| with smtplib.SMTP_SSL("smtp.gmail.com", 465) as server: |
| server.login(GMAIL_USER, GMAIL_PASS) |
| server.sendmail(GMAIL_USER, to_email, msg.as_string()) |
| except Exception as e: |
| print(f"Failed to send email: {e}") |
| raise |
|
|
| async def send_verification_email(to_email: str, full_name: str, verification_link: str): |
| content = ACCOUNT_VERIFICATION_EMAIL_CONTENT.format( |
| full_name=full_name, |
| verification_link=verification_link |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, ACCOUNT_VERIFICATION_EMAIL_SUBJECT, html) |
|
|
| async def send_password_reset_email(to_email: str, full_name: str, reset_link: str): |
| content = PASSWORD_RESET_EMAIL_CONTENT.format( |
| full_name=full_name, |
| reset_link=reset_link |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, PASSWORD_RESET_EMAIL_SUBJECT, html) |
|
|
| async def send_preorder_confirmation_email(to_email: str, full_name: str): |
| content = PREORDER_CONFIRMATION_EMAIL_CONTENT.format(full_name=full_name) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, PREORDER_CONFIRMATION_EMAIL_SUBJECT, html) |
|
|
| async def send_preorder_notification_to_owner(name: str, phone: str, gmail: str, message: str): |
| frontend_url = get_frontend_url() |
| content = PREORDER_NOTIFICATION_OWNER_CONTENT.format( |
| name=name, |
| phone=phone, |
| gmail=gmail, |
| message=message or "No message provided", |
| frontend_url=frontend_url |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor( |
| None, |
| _send_email, |
| "birdskeener@gmail.com", |
| PREORDER_NOTIFICATION_OWNER_SUBJECT, |
| html |
| ) |
|
|
| async def send_medicine_added_email(to_email: str, full_name: str, medicine_name: str, dosage: str, time: str): |
| frontend_url = get_frontend_url() |
| content = MEDICINE_ADDED_EMAIL_CONTENT.format( |
| full_name=full_name, |
| medicine_name=medicine_name, |
| dosage=dosage, |
| time=time, |
| frontend_url=frontend_url |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, MEDICINE_ADDED_EMAIL_SUBJECT, html) |
|
|
| async def send_medicine_reminder_email(to_email: str, full_name: str, medicine_name: str, dosage: str, time: str): |
| frontend_url = get_frontend_url() |
| content = MEDICINE_REMINDER_EMAIL_CONTENT.format( |
| full_name=full_name, |
| medicine_name=medicine_name, |
| dosage=dosage, |
| time=time, |
| frontend_url=frontend_url |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, MEDICINE_REMINDER_EMAIL_SUBJECT, html) |
|
|
| async def send_medicine_missed_email(to_email: str, full_name: str, medicine_name: str, dosage: str, time: str): |
| frontend_url = get_frontend_url() |
| content = MEDICINE_MISSED_EMAIL_CONTENT.format( |
| full_name=full_name, |
| medicine_name=medicine_name, |
| dosage=dosage, |
| time=time, |
| frontend_url=frontend_url |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, MEDICINE_MISSED_EMAIL_SUBJECT, html) |
|
|
| async def send_medicine_updated_email(to_email: str, full_name: str, medicine_name: str, dosage: str, time: str): |
| frontend_url = get_frontend_url() |
| content = MEDICINE_UPDATED_EMAIL_CONTENT.format( |
| full_name=full_name, |
| medicine_name=medicine_name, |
| dosage=dosage, |
| time=time, |
| frontend_url=frontend_url |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, MEDICINE_UPDATED_EMAIL_SUBJECT, html) |
|
|
| async def send_contact_confirmation_email(to_email: str, name: str, subject: str, message: str): |
| content = CONTACT_CONFIRMATION_EMAIL_CONTENT.format( |
| name=name, |
| subject=subject, |
| message=message |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, CONTACT_CONFIRMATION_EMAIL_SUBJECT, html) |
|
|
| async def send_contact_notification_to_owner(name: str, email: str, subject: str, message: str): |
| frontend_url = get_frontend_url() |
| content = CONTACT_NOTIFICATION_OWNER_CONTENT.format( |
| name=name, |
| email=email, |
| subject=subject, |
| message=message, |
| frontend_url=frontend_url |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor( |
| None, |
| _send_email, |
| "birdskeener@gmail.com", |
| CONTACT_NOTIFICATION_OWNER_SUBJECT, |
| html |
| ) |
|
|
| |
| SUBSCRIPTION_APPROVAL_EMAIL_SUBJECT = "π Subscription Approved - MediSync" |
| SUBSCRIPTION_APPROVAL_EMAIL_CONTENT = """ |
| <p class="greeting">Congratulations, {full_name}! π</p> |
| <p class="content"> |
| Your subscription to MediSync has been approved successfully! |
| </p> |
| <div class="success-box"> |
| <div class="success-box-title">β Subscription Details</div> |
| <div class="info-item">π
<strong>Plan:</strong> {plan}</div> |
| <div class="info-item">β³ <strong>Valid Until:</strong> {end_date}</div> |
| <div class="info-item">β
<strong>Status:</strong> Active</div> |
| </div> |
| <p class="content"> |
| You now have full access to all premium features. Thank you for choosing MediSync! |
| </p> |
| <div class="button-container"> |
| <a href="{frontend_url}/dashboard" class="button">Go to Dashboard</a> |
| </div> |
| """ |
|
|
| async def send_subscription_approval_email(to_email: str, full_name: str, plan: str, end_date: str): |
| frontend_url = get_frontend_url() |
| content = SUBSCRIPTION_APPROVAL_EMAIL_CONTENT.format( |
| full_name=full_name, |
| plan=plan.capitalize(), |
| end_date=end_date, |
| frontend_url=frontend_url |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, SUBSCRIPTION_APPROVAL_EMAIL_SUBJECT, html) |
|
|
| |
| PAYMENT_SUCCESS_EMAIL_SUBJECT = "β
Payment Successful - MediSync" |
| PAYMENT_SUCCESS_EMAIL_CONTENT = """ |
| <p class="greeting">Payment Received, {full_name}! β
</p> |
| <p class="content"> |
| Thank you for your payment. Your transaction was successful and your subscription is now active! |
| </p> |
| <div class="success-box"> |
| <div class="success-box-title">π§Ύ Transaction Receipt</div> |
| <div class="info-item">π³ <strong>Transaction ID:</strong> {transaction_id}</div> |
| <div class="info-item">π
<strong>Plan:</strong> {plan_name}</div> |
| <div class="info-item">π° <strong>Amount:</strong> {amount}</div> |
| <div class="info-item">ποΈ <strong>Date:</strong> {date}</div> |
| </div> |
| <p class="content"> |
| You can now enjoy all the benefits of your {plan_name}. |
| </p> |
| <div class="button-container"> |
| <a href="{frontend_url}/dashboard" class="button">Go to Dashboard</a> |
| </div> |
| <p class="content" style="font-size: 14px; color: #64748b; text-align: center;"> |
| A copy of this receipt has been saved to your account. |
| </p> |
| """ |
|
|
| async def send_payment_success_email(to_email: str, full_name: str, transaction_id: str, plan_name: str, amount: str, date: str): |
| frontend_url = get_frontend_url() |
| content = PAYMENT_SUCCESS_EMAIL_CONTENT.format( |
| full_name=full_name, |
| transaction_id=transaction_id, |
| plan_name=plan_name, |
| amount=amount, |
| date=date, |
| frontend_url=frontend_url |
| ) |
| html = EMAIL_BASE_TEMPLATE.format(content=content) |
| loop = asyncio.get_event_loop() |
| await loop.run_in_executor(None, _send_email, to_email, PAYMENT_SUCCESS_EMAIL_SUBJECT, html) |
|
|
|
|