NewsLetter / services /email_service.py
SmartHeal's picture
Upload 19 files
a19173c verified
import os
import smtplib
import logging
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from typing import List
class EmailService:
"""Professional email service for newsletter distribution"""
def __init__(self):
self.smtp_server = os.getenv("SMTP_SERVER", "smtp.gmail.com")
self.smtp_port = int(os.getenv("SMTP_PORT", "587"))
self.email_user = os.getenv("EMAIL_USER", "newsletter@professional.com")
self.email_password = os.getenv("EMAIL_PASSWORD", "dummy_password")
def send_newsletter(self, newsletter_html: str, recipients: List[str], topic: str) -> str:
"""Send professional newsletter to recipients"""
try:
# Validate recipients
valid_recipients = [email.strip() for email in recipients if self._is_valid_email(email.strip())]
if not valid_recipients:
return "❌ No valid email addresses provided"
# Setup email
msg = MIMEMultipart('alternative')
msg['From'] = self.email_user
msg['Subject'] = f"Professional Newsletter: {topic}"
# Create both plain text and HTML versions
plain_text = self._html_to_text(newsletter_html)
# Attach parts
part1 = MIMEText(plain_text, 'plain')
part2 = MIMEText(newsletter_html, 'html')
msg.attach(part1)
msg.attach(part2)
# Send emails
success_count = 0
failed_recipients = []
with smtplib.SMTP(self.smtp_server, self.smtp_port) as server:
server.starttls()
server.login(self.email_user, self.email_password)
for recipient in valid_recipients:
try:
msg['To'] = recipient
server.send_message(msg)
success_count += 1
logging.info(f"Newsletter sent successfully to {recipient}")
# Remove To header for next iteration
del msg['To']
except Exception as e:
failed_recipients.append(recipient)
logging.error(f"Failed to send to {recipient}: {e}")
# Return status
if success_count == len(valid_recipients):
return f"✅ Newsletter sent successfully to all {success_count} recipients"
else:
return f"⚠️ Newsletter sent to {success_count}/{len(valid_recipients)} recipients. Failed: {', '.join(failed_recipients)}"
except Exception as e:
logging.error(f"Email service error: {e}")
return f"❌ Failed to send newsletter: {str(e)}"
def _is_valid_email(self, email: str) -> bool:
"""Validate email address format"""
import re
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
def _html_to_text(self, html: str) -> str:
"""Convert HTML to plain text for email compatibility"""
import re
# Simple HTML to text conversion
text = re.sub(r'<[^>]+>', '', html) # Remove HTML tags
text = re.sub(r'\s+', ' ', text) # Normalize whitespace
text = text.strip()
return text
def create_professional_email_template(self, newsletter_content: str, topic: str) -> str:
"""Create professional email template"""
return f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Professional Newsletter: {topic}</title>
</head>
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 0 auto;">
<div style="background: #f8f9fa; padding: 20px; text-align: center; border-bottom: 3px solid #007bff;">
<h1 style="color: #007bff; margin: 0;">Professional Newsletter</h1>
<p style="margin: 5px 0; color: #666;">Data-Driven Insights & Analysis</p>
</div>
<div style="padding: 20px;">
{newsletter_content}
</div>
<div style="background: #f8f9fa; padding: 20px; text-align: center; border-top: 1px solid #ddd; margin-top: 30px;">
<p style="margin: 0; color: #666; font-size: 0.9em;">
This newsletter was generated using advanced AI research and data analysis.
<br>
For questions or feedback, please contact our research team.
</p>
</div>
</body>
</html>
"""
def schedule_newsletter(self, newsletter_html: str, recipients: List[str], topic: str, schedule_time: str) -> str:
"""Schedule newsletter for future delivery (placeholder for future implementation)"""
return "📅 Newsletter scheduling feature coming soon. Please send immediately for now."
def get_email_analytics(self) -> dict:
"""Get email delivery analytics (placeholder for future implementation)"""
return {
"total_sent": 0,
"delivery_rate": "N/A",
"open_rate": "N/A",
"click_rate": "N/A"
}