mirror of
https://github.com/lightningcell/flask-2fa-auth.git
synced 2026-05-26 15:13:35 +00:00
205 lines
6.7 KiB
Python
205 lines
6.7 KiB
Python
"""
|
|
Modular mail service for Flask 2FA application.
|
|
|
|
This module provides a reusable mail service that can be used for:
|
|
- Suspicious login alerts
|
|
- Location approval requests
|
|
- Account security notifications
|
|
- General application notifications
|
|
|
|
Security features:
|
|
- HTML email with security headers
|
|
- Secure token handling
|
|
- Rate limiting support
|
|
- Template-based emails
|
|
"""
|
|
|
|
import logging
|
|
from flask import current_app, render_template, url_for
|
|
from flask_mail import Mail, Message
|
|
from datetime import datetime, timedelta
|
|
from typing import Optional, List, Dict, Any
|
|
|
|
|
|
class MailService:
|
|
"""
|
|
Centralized mail service for the application.
|
|
|
|
Provides secure email functionality with template support
|
|
and security best practices.
|
|
"""
|
|
|
|
def __init__(self, mail_instance: Optional[Mail] = None):
|
|
"""
|
|
Initialize mail service.
|
|
|
|
Args:
|
|
mail_instance: Flask-Mail instance (optional)
|
|
"""
|
|
self.mail = mail_instance
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
def init_app(self, app, mail_instance: Mail):
|
|
"""Initialize mail service with Flask app and Mail instance."""
|
|
self.mail = mail_instance
|
|
with app.app_context():
|
|
self.logger.info("Mail service initialized")
|
|
|
|
def send_email(self,
|
|
subject: str,
|
|
recipients: List[str],
|
|
template: str,
|
|
**template_vars) -> bool:
|
|
"""
|
|
Send an email using template.
|
|
|
|
Args:
|
|
subject: Email subject line
|
|
recipients: List of recipient email addresses
|
|
template: Template name (without .html extension)
|
|
**template_vars: Variables to pass to template
|
|
|
|
Returns:
|
|
bool: True if email sent successfully, False otherwise
|
|
"""
|
|
try:
|
|
# Create message
|
|
msg = Message(
|
|
subject=subject,
|
|
recipients=recipients,
|
|
sender=current_app.config['MAIL_DEFAULT_SENDER']
|
|
)
|
|
|
|
# Render HTML template
|
|
msg.html = render_template(f'emails/{template}.html', **template_vars)
|
|
|
|
# Add security headers to email
|
|
msg.extra_headers = {
|
|
'X-Mailer': 'Flask-2FA-App',
|
|
'X-Priority': '1',
|
|
'X-MSMail-Priority': 'High'
|
|
}
|
|
|
|
# Send email
|
|
self.mail.send(msg)
|
|
|
|
self.logger.info(f"Email sent successfully to {recipients}: {subject}")
|
|
return True
|
|
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to send email to {recipients}: {str(e)}")
|
|
return False
|
|
|
|
def send_suspicious_login_alert(self,
|
|
user_email: str,
|
|
user_name: str,
|
|
location_data: Dict[str, Any],
|
|
approval_token: str) -> bool:
|
|
"""
|
|
Send suspicious login alert email.
|
|
|
|
Args:
|
|
user_email: User's email address
|
|
user_name: User's display name
|
|
location_data: Dictionary containing location information
|
|
approval_token: Token for approving the location
|
|
|
|
Returns:
|
|
bool: True if email sent successfully
|
|
"""
|
|
approval_url = url_for('auth.approve_location',
|
|
token=approval_token,
|
|
_external=True)
|
|
|
|
return self.send_email(
|
|
subject="🔐 Suspicious Login Detected - Action Required",
|
|
recipients=[user_email],
|
|
template="suspicious_login",
|
|
user_name=user_name,
|
|
location=location_data,
|
|
approval_url=approval_url,
|
|
login_time=datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'),
|
|
app_name="Flask 2FA App"
|
|
)
|
|
|
|
def send_location_approved_notification(self,
|
|
user_email: str,
|
|
user_name: str,
|
|
location_data: Dict[str, Any]) -> bool:
|
|
"""
|
|
Send location approval confirmation email.
|
|
|
|
Args:
|
|
user_email: User's email address
|
|
user_name: User's display name
|
|
location_data: Dictionary containing location information
|
|
|
|
Returns:
|
|
bool: True if email sent successfully
|
|
"""
|
|
return self.send_email(
|
|
subject="✅ Login Location Approved",
|
|
recipients=[user_email],
|
|
template="location_approved",
|
|
user_name=user_name,
|
|
location=location_data,
|
|
approval_time=datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'),
|
|
app_name="Flask 2FA App"
|
|
)
|
|
|
|
def send_account_security_alert(self,
|
|
user_email: str,
|
|
user_name: str,
|
|
alert_type: str,
|
|
details: Dict[str, Any]) -> bool:
|
|
"""
|
|
Send general account security alert.
|
|
|
|
Args:
|
|
user_email: User's email address
|
|
user_name: User's display name
|
|
alert_type: Type of security alert
|
|
details: Additional details for the alert
|
|
|
|
Returns:
|
|
bool: True if email sent successfully
|
|
"""
|
|
return self.send_email(
|
|
subject=f"🔔 Security Alert: {alert_type}",
|
|
recipients=[user_email],
|
|
template="security_alert",
|
|
user_name=user_name,
|
|
alert_type=alert_type,
|
|
details=details,
|
|
timestamp=datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'),
|
|
app_name="Flask 2FA App"
|
|
)
|
|
|
|
def send_welcome_email(self,
|
|
user_email: str,
|
|
user_name: str) -> bool:
|
|
"""
|
|
Send welcome email to new users.
|
|
|
|
Args:
|
|
user_email: User's email address
|
|
user_name: User's display name
|
|
|
|
Returns:
|
|
bool: True if email sent successfully
|
|
"""
|
|
dashboard_url = url_for('main.dashboard', _external=True)
|
|
|
|
return self.send_email(
|
|
subject="🎉 Welcome to Flask 2FA App!",
|
|
recipients=[user_email],
|
|
template="welcome",
|
|
user_name=user_name,
|
|
dashboard_url=dashboard_url,
|
|
app_name="Flask 2FA App"
|
|
)
|
|
|
|
|
|
# Global mail service instance
|
|
mail_service = MailService()
|