"""Email service. Uses database settings from Admin panel instead of environment variables. """ import logging import smtplib from datetime import UTC, datetime from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from flask import current_app, render_template, url_for logger = logging.getLogger(__name__) def get_mail_config(): """Get mail configuration from database. Returns: dict: Mail configuration from database or defaults """ try: from customer_portal.models import get_db from customer_portal.models.settings import PortalSettings db = get_db() return PortalSettings.get_mail_config(db) except Exception as e: logger.error(f"Failed to get mail config from database: {e}") # Fallback to app config (environment variables) return { "mail_server": current_app.config.get("MAIL_SERVER", ""), "mail_port": current_app.config.get("MAIL_PORT", 587), "mail_use_tls": current_app.config.get("MAIL_USE_TLS", True), "mail_use_ssl": current_app.config.get("MAIL_USE_SSL", False), "mail_username": current_app.config.get("MAIL_USERNAME", ""), "mail_password": current_app.config.get("MAIL_PASSWORD", ""), "mail_default_sender": current_app.config.get("MAIL_DEFAULT_SENDER", ""), "mail_default_sender_name": "Kundenportal", } def send_email(to: str, subject: str, html_body: str, text_body: str = "") -> bool: """Send email using database SMTP settings. Args: to: Recipient email address subject: Email subject html_body: HTML content text_body: Plain text content (optional) Returns: True if sent successfully, False otherwise """ config = get_mail_config() if not config.get("mail_server"): logger.error("Mail server not configured") return False try: # Create message msg = MIMEMultipart("alternative") msg["Subject"] = subject msg["To"] = to # Build sender sender_name = config.get("mail_default_sender_name", "Kundenportal") sender_email = config.get("mail_default_sender", "") if sender_name and sender_email: msg["From"] = f"{sender_name} <{sender_email}>" else: msg["From"] = sender_email # Add plain text if text_body: msg.attach(MIMEText(text_body, "plain", "utf-8")) # Add HTML msg.attach(MIMEText(html_body, "html", "utf-8")) # Connect to SMTP server server = config.get("mail_server") port = config.get("mail_port", 587) use_ssl = config.get("mail_use_ssl", False) use_tls = config.get("mail_use_tls", True) if use_ssl: smtp = smtplib.SMTP_SSL(server, port) else: smtp = smtplib.SMTP(server, port) if use_tls: smtp.starttls() # Login if credentials provided username = config.get("mail_username") password = config.get("mail_password") if username and password: smtp.login(username, password) # Send smtp.sendmail(sender_email, [to], msg.as_string()) smtp.quit() logger.info(f"Email sent to {to}: {subject}") return True except Exception as e: logger.error(f"Failed to send email to {to}: {e}") return False class EmailService: """Send emails using database SMTP settings.""" SUBJECT_MAP = { "login": "Ihr Login-Code fuer das Kundenportal", "register": "Willkommen - Ihre Registrierung", "reset": "Ihr Code zum Zuruecksetzen", "prefill": "Ihr Code fuer die Buchung", } @staticmethod def send_otp(email: str, code: str, purpose: str = "login") -> bool: """Send OTP code via email. Args: email: Recipient email address code: OTP code purpose: OTP purpose (login, register, reset, prefill) Returns: True if sent successfully, False otherwise """ subject = EmailService.SUBJECT_MAP.get(purpose, "Ihr Code") html_body = render_template( "emails/otp.html", code=code, purpose=purpose, ) text_body = f""" Ihr Code: {code} Dieser Code ist 10 Minuten gueltig. Falls Sie diesen Code nicht angefordert haben, ignorieren Sie diese E-Mail. """ success = send_email(email, subject, html_body, text_body) if success: logger.info(f"OTP email sent to {email} for {purpose}") # In development, log the code for testing elif current_app.debug: logger.warning(f"DEBUG MODE - OTP code for {email}: {code}") return success @staticmethod def send_login_notification(email: str, ip_address: str, user_agent: str) -> bool: """Send notification about new login. Args: email: Recipient email address ip_address: Login IP address user_agent: Browser user agent Returns: True if sent successfully """ html_body = render_template( "emails/login_notification.html", ip_address=ip_address, user_agent=user_agent, ) return send_email(email, "Neue Anmeldung in Ihrem Kundenportal", html_body) @staticmethod def send_welcome(email: str, name: str) -> bool: """Send welcome email after registration. Args: email: Recipient email address name: Customer name Returns: True if sent successfully, False otherwise """ # Get portal URL from config or build it portal_url = current_app.config.get("PORTAL_URL", "") if not portal_url: try: portal_url = url_for("main.index", _external=True) except RuntimeError: portal_url = "http://localhost:8502" html_body = render_template( "emails/welcome.html", name=name, portal_url=portal_url, year=datetime.now(UTC).year, ) text_body = f""" Willkommen, {name}! Ihr Kundenkonto wurde erfolgreich erstellt. Im Kundenportal koennen Sie: - Ihre Buchungen einsehen - Rechnungen herunterladen - Videos ansehen - Stornierungen beantragen Zum Portal: {portal_url} """ success = send_email( email, "Willkommen im Kundenportal - Webwerkstatt", html_body, text_body ) if success: logger.info(f"Welcome email sent to {email}") elif current_app.debug: logger.warning(f"DEBUG MODE - Welcome email would be sent to {email}") return success # Keep Flask-Mail for backwards compatibility (but not used anymore) from flask_mail import Mail mail = Mail()