forked from andika/membership-be
first commit
This commit is contained in:
182
email_service.py
Normal file
182
email_service.py
Normal file
@@ -0,0 +1,182 @@
|
||||
import os
|
||||
from email.mime.text import MIMEText
|
||||
from email.mime.multipart import MIMEMultipart
|
||||
import aiosmtplib
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
SMTP_HOST = os.environ.get('SMTP_HOST', 'smtp.gmail.com')
|
||||
SMTP_PORT = int(os.environ.get('SMTP_PORT', 587))
|
||||
SMTP_USERNAME = os.environ.get('SMTP_USERNAME', '')
|
||||
SMTP_PASSWORD = os.environ.get('SMTP_PASSWORD', '')
|
||||
SMTP_FROM_EMAIL = os.environ.get('SMTP_FROM_EMAIL', 'noreply@membership.com')
|
||||
SMTP_FROM_NAME = os.environ.get('SMTP_FROM_NAME', 'Membership Platform')
|
||||
FRONTEND_URL = os.environ.get('FRONTEND_URL', 'http://localhost:3000')
|
||||
|
||||
async def send_email(to_email: str, subject: str, html_content: str):
|
||||
"""Send an email using SMTP"""
|
||||
try:
|
||||
message = MIMEMultipart('alternative')
|
||||
message['From'] = f"{SMTP_FROM_NAME} <{SMTP_FROM_EMAIL}>"
|
||||
message['To'] = to_email
|
||||
message['Subject'] = subject
|
||||
|
||||
html_part = MIMEText(html_content, 'html')
|
||||
message.attach(html_part)
|
||||
|
||||
# For development/testing, just log the email
|
||||
if not SMTP_USERNAME or not SMTP_PASSWORD:
|
||||
logger.info(f"[EMAIL] To: {to_email}")
|
||||
logger.info(f"[EMAIL] Subject: {subject}")
|
||||
logger.info(f"[EMAIL] Content: {html_content}")
|
||||
return True
|
||||
|
||||
# Send actual email
|
||||
await aiosmtplib.send(
|
||||
message,
|
||||
hostname=SMTP_HOST,
|
||||
port=SMTP_PORT,
|
||||
username=SMTP_USERNAME,
|
||||
password=SMTP_PASSWORD,
|
||||
start_tls=True
|
||||
)
|
||||
logger.info(f"Email sent successfully to {to_email}")
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to send email to {to_email}: {str(e)}")
|
||||
return False
|
||||
|
||||
async def send_verification_email(to_email: str, token: str):
|
||||
"""Send email verification link"""
|
||||
verification_url = f"{FRONTEND_URL}/verify-email?token={token}"
|
||||
subject = "Verify Your Email Address"
|
||||
html_content = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{ font-family: 'DM Sans', Arial, sans-serif; line-height: 1.6; color: #3D405B; }}
|
||||
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
|
||||
.header {{ background: linear-gradient(135deg, #F2CC8F 0%, #E07A5F 100%); padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }}
|
||||
.header h1 {{ color: white; margin: 0; font-family: 'Fraunces', serif; }}
|
||||
.content {{ background: #FDFCF8; padding: 30px; border-radius: 0 0 10px 10px; }}
|
||||
.button {{ display: inline-block; background: #E07A5F; color: white; padding: 15px 40px; text-decoration: none; border-radius: 50px; font-weight: 600; margin: 20px 0; }}
|
||||
.button:hover {{ background: #D0694E; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Welcome to Our Community!</h1>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>Thank you for registering with us. We're excited to have you join our community.</p>
|
||||
<p>Please click the button below to verify your email address:</p>
|
||||
<p style="text-align: center;">
|
||||
<a href="{verification_url}" class="button">Verify Email</a>
|
||||
</p>
|
||||
<p>Or copy and paste this link into your browser:</p>
|
||||
<p style="word-break: break-all; color: #6B708D;">{verification_url}</p>
|
||||
<p>This link will expire in 24 hours.</p>
|
||||
<p>If you didn't create an account, please ignore this email.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return await send_email(to_email, subject, html_content)
|
||||
|
||||
async def send_approval_notification(to_email: str, first_name: str):
|
||||
"""Send notification when user is approved"""
|
||||
login_url = f"{FRONTEND_URL}/login"
|
||||
subject = "Your Membership Application Has Been Approved!"
|
||||
html_content = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{ font-family: 'DM Sans', Arial, sans-serif; line-height: 1.6; color: #3D405B; }}
|
||||
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
|
||||
.header {{ background: linear-gradient(135deg, #F2CC8F 0%, #E07A5F 100%); padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }}
|
||||
.header h1 {{ color: white; margin: 0; font-family: 'Fraunces', serif; }}
|
||||
.content {{ background: #FDFCF8; padding: 30px; border-radius: 0 0 10px 10px; }}
|
||||
.button {{ display: inline-block; background: #E07A5F; color: white; padding: 15px 40px; text-decoration: none; border-radius: 50px; font-weight: 600; margin: 20px 0; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Congratulations, {first_name}!</h1>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>Great news! Your membership application has been approved.</p>
|
||||
<p>You now have full access to all member features and events.</p>
|
||||
<p style="text-align: center;">
|
||||
<a href="{login_url}" class="button">Login to Your Account</a>
|
||||
</p>
|
||||
<p>We look forward to seeing you at our events!</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return await send_email(to_email, subject, html_content)
|
||||
|
||||
async def send_payment_prompt_email(to_email: str, first_name: str):
|
||||
"""Send payment prompt email after admin approval"""
|
||||
payment_url = f"{FRONTEND_URL}/plans"
|
||||
subject = "Complete Your LOAF Membership - Payment Required"
|
||||
html_content = f"""
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {{ font-family: 'DM Sans', Arial, sans-serif; line-height: 1.6; color: #3D405B; }}
|
||||
.container {{ max-width: 600px; margin: 0 auto; padding: 20px; }}
|
||||
.header {{ background: linear-gradient(135deg, #F2CC8F 0%, #E07A5F 100%); padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }}
|
||||
.header h1 {{ color: white; margin: 0; font-family: 'Fraunces', serif; }}
|
||||
.content {{ background: #FDFCF8; padding: 30px; border-radius: 0 0 10px 10px; }}
|
||||
.button {{ display: inline-block; background: #E07A5F; color: white; padding: 15px 40px; text-decoration: none; border-radius: 50px; font-weight: 600; margin: 20px 0; }}
|
||||
.button:hover {{ background: #D0694E; }}
|
||||
.benefits {{ background: white; padding: 20px; border-radius: 8px; margin: 20px 0; }}
|
||||
.benefits ul {{ list-style: none; padding: 0; }}
|
||||
.benefits li {{ padding: 8px 0; padding-left: 25px; position: relative; }}
|
||||
.benefits li:before {{ content: "✓"; position: absolute; left: 0; color: #E07A5F; font-weight: bold; }}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>🎉 You're Approved, {first_name}!</h1>
|
||||
</div>
|
||||
<div class="content">
|
||||
<p><strong>Great news!</strong> Your LOAF membership application has been approved by our admin team.</p>
|
||||
|
||||
<p>To activate your membership and gain full access, please complete your annual membership payment:</p>
|
||||
|
||||
<p style="text-align: center;">
|
||||
<a href="{payment_url}" class="button">Complete Payment →</a>
|
||||
</p>
|
||||
|
||||
<div class="benefits">
|
||||
<p><strong>Once payment is processed, you'll have immediate access to:</strong></p>
|
||||
<ul>
|
||||
<li>Members-only events and gatherings</li>
|
||||
<li>Community directory and networking</li>
|
||||
<li>Exclusive member benefits and discounts</li>
|
||||
<li>LOAF newsletter and updates</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p>We're excited to have you join the LOAF community!</p>
|
||||
|
||||
<p style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #E8E4DB; color: #6B708D; font-size: 14px;">
|
||||
Questions? Contact us at support@loaf.org
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
return await send_email(to_email, subject, html_content)
|
||||
Reference in New Issue
Block a user