Your IP : 216.73.217.79


Current Path : /var/www/cesa.co.za/python/app/services/
Upload File :
Current File : /var/www/cesa.co.za/python/app/services/mail.py

#!/usr/bin/env python3
"""
Mail Service for IGA Core Python Applications

This module provides a mail service class that uses Python-specific configuration
and sends emails using the configured SMTP server.
"""

import os
import smtplib
import ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from typing import List, Optional, Dict, Any
from pathlib import Path

# Import our configuration
import sys
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from config import get_mail_config


class SymfonyMailService:
    """
    Mail service class that uses Python-specific configuration
    and provides methods to send emails.
    """
    
    def __init__(self, config: Optional[Dict[str, Any]] = None):
        """
        Initialize the mail service.
        
        Args:
            config: Optional custom mail configuration. If None, uses default config.
        """
        self.config = config or get_mail_config()
        self._validate_config()
    
    def _validate_config(self):
        """Validate the loaded SMTP configuration."""
        if not self.config.get('smtp_host'):
            raise ValueError("SMTP host not configured")
        
        if not self.config.get('smtp_port'):
            raise ValueError("SMTP port not configured")
        
        if self.config.get('auth_required') and not self.config.get('smtp_username'):
            raise ValueError("SMTP authentication required but username not provided")
    
    def send_email(self, 
                   to_email: str, 
                   subject: str, 
                   body: str, 
                   from_email: Optional[str] = None,
                   cc: Optional[List[str]] = None,
                   bcc: Optional[List[str]] = None,
                   attachments: Optional[List[str]] = None,
                   html_body: Optional[str] = None) -> bool:
        """
        Send an email using the configured SMTP server.
        
        Args:
            to_email: Recipient email address
            subject: Email subject
            body: Plain text email body
            from_email: Sender email address (optional, will use default if not provided)
            cc: List of CC recipients
            bcc: List of BCC recipients
            attachments: List of file paths to attach
            html_body: HTML version of the email body (optional)
        
        Returns:
            bool: True if email sent successfully, False otherwise
        """
        try:
            # Create message
            msg = MIMEMultipart('alternative')
            msg['Subject'] = subject
            msg['To'] = to_email
            
            # Set sender
            if from_email:
                msg['From'] = from_email
            else:
                msg['From'] = f"{self.config.get('from_name', 'Python Mail Service')} <{self.config.get('from_email', 'noreply@yourdomain.com')}>"
            
            if cc:
                msg['Cc'] = ', '.join(cc)
            
            # Add plain text body
            text_part = MIMEText(body, 'plain', 'utf-8')
            msg.attach(text_part)
            
            # Add HTML body if provided
            if html_body:
                html_part = MIMEText(html_body, 'html', 'utf-8')
                msg.attach(html_part)
            
            # Add attachments
            if attachments:
                for attachment_path in attachments:
                    self._add_attachment(msg, attachment_path)
            
            # Prepare recipients list
            recipients = [to_email]
            if cc:
                recipients.extend(cc)
            if bcc:
                recipients.extend(bcc)
            
            # Send email
            print(f"[DEBUG MAIL] Attempting to send email to: {to_email}")
            result = self._send_via_smtp(msg, recipients)
            print(f"[DEBUG MAIL] _send_via_smtp returned: {result}")
            return result
            
        except Exception as e:
            print(f"[ERROR MAIL] Error sending mail: {type(e).__name__}: {str(e)}")
            import traceback
            print(f"[ERROR MAIL] Traceback:")
            traceback.print_exc()
            return False
    
    def _add_attachment(self, msg: MIMEMultipart, file_path: str):
        """Add a file attachment to the email message."""
        try:
            with open(file_path, 'rb') as attachment:
                part = MIMEBase('application', 'octet-stream')
                part.set_payload(attachment.read())
            
            encoders.encode_base64(part)
            part.add_header(
                'Content-Disposition',
                f'attachment; filename= {os.path.basename(file_path)}'
            )
            msg.attach(part)
        except Exception:
            pass
    
    def _send_via_smtp(self, msg: MIMEMultipart, recipients: List[str]) -> bool:
        """Send the email message via SMTP."""
        try:
            print(f"[DEBUG SMTP] Connecting to {self.config['smtp_host']}:{self.config['smtp_port']}")
            print(f"[DEBUG SMTP] Use SSL: {self.config.get('use_ssl')}, Use TLS: {self.config.get('use_tls')}")
            
            if self.config.get('use_ssl'):
                # Use SSL connection
                print("[DEBUG SMTP] Creating SMTP_SSL connection...")
                server = smtplib.SMTP_SSL(
                    self.config['smtp_host'], 
                    self.config['smtp_port']
                )
                print("[DEBUG SMTP] SMTP_SSL connection established")
            else:
                # Use regular connection
                print("[DEBUG SMTP] Creating SMTP connection...")
                server = smtplib.SMTP(
                    self.config['smtp_host'], 
                    self.config['smtp_port']
                )
                print("[DEBUG SMTP] SMTP connection established")
                
                # Start TLS if required
                if self.config.get('use_tls'):
                    print("[DEBUG SMTP] Starting TLS...")
                    server.starttls(context=ssl.create_default_context())
                    print("[DEBUG SMTP] TLS started")
            
            # Login if authentication is required
            if self.config.get('auth_required'):
                print(f"[DEBUG SMTP] Authenticating as {self.config['smtp_username']}...")
                server.login(
                    self.config['smtp_username'], 
                    self.config['smtp_password']
                )
                print("[DEBUG SMTP] Authentication successful")
            else:
                print("[DEBUG SMTP] No authentication required")
            
            # Send email
            print(f"[DEBUG SMTP] Sending message to recipients: {recipients}")
            server.send_message(msg)
            print("[DEBUG SMTP] Message sent successfully")
            server.quit()
            print("[DEBUG SMTP] Connection closed")
            
            return True
            
        except Exception as e:
            print(f"[ERROR SMTP] Error sending mail: {type(e).__name__}: {str(e)}")
            import traceback
            print(f"[ERROR SMTP] Traceback:")
            traceback.print_exc()
            return False
    
    def test_connection(self) -> bool:
        """Test the SMTP connection without sending an email."""
        try:
            if self.config.get('use_ssl'):
                server = smtplib.SMTP_SSL(
                    self.config['smtp_host'], 
                    self.config['smtp_port']
                )
            else:
                server = smtplib.SMTP(
                    self.config['smtp_host'], 
                    self.config['smtp_port']
                )
                
                if self.config.get('use_tls'):
                    server.starttls(context=ssl.create_default_context())
            
            if self.config.get('auth_required'):
                server.login(
                    self.config['smtp_username'], 
                    self.config['smtp_password']
                )
            
            server.quit()
            return True
            
        except Exception:
            return False
    
    def get_config(self) -> Dict[str, Any]:
        """Get the current SMTP configuration (without sensitive data)."""
        config = self.config.copy()
        if 'smtp_password' in config:
            config['smtp_password'] = '***' if config['smtp_password'] else None
        return config


# Convenience function for quick email sending
def send_quick_email(to_email: str, subject: str, body: str, **kwargs) -> bool:
    """
    Quick function to send an email using default configuration.
    
    Args:
        to_email: Recipient email address
        subject: Email subject
        body: Email body
        **kwargs: Additional arguments passed to SymfonyMailService.send_email()
    
    Returns:
        bool: True if email sent successfully, False otherwise
    """
    mail_service = SymfonyMailService()
    return mail_service.send_email(to_email, subject, body, **kwargs)


# Example usage and testing
if __name__ == "__main__":
    # Example usage
    try:
        # Create mail service instance
        mail_service = SymfonyMailService()
        
        # Test connection
        if mail_service.test_connection():
            print("SMTP connection successful!")
            
            # Send a test email
            success = mail_service.send_email(
                to_email="test@example.com",
                subject="Test Email from IGA Core",
                body="This is a test email sent from the IGA Core Symfony application.",
                html_body="<h1>Test Email</h1><p>This is a test email sent from the <strong>IGA Core Symfony</strong> application.</p>"
            )
            
            if success:
                print("Test email sent successfully!")
            else:
                print("Failed to send test email.")
        else:
            print("SMTP connection failed!")
            
    except Exception as e:
        print(f"Error: {e}")