| Current Path : /home/otto/python/app/services/ |
| Current File : //home/otto/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
return self._send_via_smtp(msg, recipients)
except Exception as e:
print("Error sending mail: " + str(e))
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:
if self.config.get('use_ssl'):
# Use SSL connection
server = smtplib.SMTP_SSL(
self.config['smtp_host'],
self.config['smtp_port']
)
else:
# Use regular connection
server = smtplib.SMTP(
self.config['smtp_host'],
self.config['smtp_port']
)
# Start TLS if required
if self.config.get('use_tls'):
server.starttls(context=ssl.create_default_context())
# Login if authentication is required
if self.config.get('auth_required'):
server.login(
self.config['smtp_username'],
self.config['smtp_password']
)
# Send email
server.send_message(msg)
server.quit()
return True
except Exception:
print("Error sending mail: " + str(sys.exc_info()[1]))
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}")