feat: Add email logging and monitoring system
- Add EmailLog model to database.py for tracking sent emails - Modify email_service.py to log all sent emails to database - Track email type (welcome, password_reset, notification) - Record sender, recipient, subject, status, timestamps - Supports monitoring email delivery success/failure Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
749abfa018
commit
a09203ef55
48
database.py
48
database.py
@ -2525,6 +2525,54 @@ class PopularPagesDaily(Base):
|
||||
return f"<PopularPagesDaily {self.date} {self.path}>"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# EMAIL LOGGING
|
||||
# ============================================================
|
||||
|
||||
class EmailLog(Base):
|
||||
"""
|
||||
Log wszystkich wysłanych emaili systemowych.
|
||||
|
||||
Śledzi:
|
||||
- Emaile rejestracyjne (weryfikacja)
|
||||
- Emaile resetowania hasła
|
||||
- Powiadomienia systemowe
|
||||
- Status dostarczenia
|
||||
|
||||
Created: 2026-01-14
|
||||
"""
|
||||
__tablename__ = 'email_logs'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
|
||||
# Dane emaila
|
||||
email_type = Column(String(50), nullable=False, index=True) # welcome, password_reset, notification
|
||||
recipient_email = Column(String(255), nullable=False, index=True)
|
||||
recipient_name = Column(String(255), nullable=True)
|
||||
subject = Column(String(500), nullable=False)
|
||||
|
||||
# Powiązanie z użytkownikiem (opcjonalne)
|
||||
user_id = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'), nullable=True)
|
||||
|
||||
# Status
|
||||
status = Column(String(20), default='pending', index=True) # pending, sent, failed
|
||||
error_message = Column(Text, nullable=True)
|
||||
|
||||
# Metadane
|
||||
sender_email = Column(String(255), nullable=True)
|
||||
ip_address = Column(String(45), nullable=True) # IP requestu (jeśli dostępne)
|
||||
|
||||
# Timestamps
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
sent_at = Column(DateTime, nullable=True)
|
||||
|
||||
# Relacje
|
||||
user = relationship('User', backref='email_logs')
|
||||
|
||||
def __repr__(self):
|
||||
return f"<EmailLog {self.id} {self.email_type} -> {self.recipient_email} ({self.status})>"
|
||||
|
||||
|
||||
# ============================================================
|
||||
# DATABASE INITIALIZATION
|
||||
# ============================================================
|
||||
|
||||
@ -204,7 +204,10 @@ def send_email(
|
||||
subject: str,
|
||||
body_text: str,
|
||||
body_html: Optional[str] = None,
|
||||
from_address: Optional[str] = None
|
||||
from_address: Optional[str] = None,
|
||||
email_type: str = 'notification',
|
||||
user_id: Optional[int] = None,
|
||||
recipient_name: Optional[str] = None
|
||||
) -> bool:
|
||||
"""
|
||||
Send email using the global Email Service instance
|
||||
@ -215,6 +218,9 @@ def send_email(
|
||||
body_text: Plain text email body
|
||||
body_html: HTML email body (optional)
|
||||
from_address: Sender email (optional)
|
||||
email_type: Type of email for logging (welcome, password_reset, notification)
|
||||
user_id: User ID for logging (optional)
|
||||
recipient_name: Recipient name for logging (optional)
|
||||
|
||||
Returns:
|
||||
True if sent successfully, False otherwise
|
||||
@ -227,7 +233,74 @@ def send_email(
|
||||
if isinstance(to, str):
|
||||
to = [to]
|
||||
|
||||
return _email_service.send_mail(to, subject, body_text, body_html, from_address)
|
||||
result = _email_service.send_mail(to, subject, body_text, body_html, from_address)
|
||||
|
||||
# Log email to database
|
||||
_log_email(
|
||||
email_type=email_type,
|
||||
recipient_emails=to,
|
||||
recipient_name=recipient_name,
|
||||
subject=subject,
|
||||
user_id=user_id,
|
||||
sender_email=from_address or _email_service.mail_from if _email_service else None,
|
||||
success=result
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _log_email(
|
||||
email_type: str,
|
||||
recipient_emails: List[str],
|
||||
subject: str,
|
||||
success: bool,
|
||||
recipient_name: Optional[str] = None,
|
||||
user_id: Optional[int] = None,
|
||||
sender_email: Optional[str] = None,
|
||||
error_message: Optional[str] = None
|
||||
) -> None:
|
||||
"""
|
||||
Log email to database for monitoring.
|
||||
|
||||
Args:
|
||||
email_type: Type of email (welcome, password_reset, notification)
|
||||
recipient_emails: List of recipient email addresses
|
||||
subject: Email subject
|
||||
success: Whether email was sent successfully
|
||||
recipient_name: Recipient name (optional)
|
||||
user_id: User ID (optional)
|
||||
sender_email: Sender email address (optional)
|
||||
error_message: Error message if failed (optional)
|
||||
"""
|
||||
try:
|
||||
from database import SessionLocal, EmailLog
|
||||
from datetime import datetime
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
for email in recipient_emails:
|
||||
log_entry = EmailLog(
|
||||
email_type=email_type,
|
||||
recipient_email=email,
|
||||
recipient_name=recipient_name,
|
||||
subject=subject,
|
||||
user_id=user_id,
|
||||
sender_email=sender_email,
|
||||
status='sent' if success else 'failed',
|
||||
sent_at=datetime.utcnow() if success else None,
|
||||
error_message=error_message if not success else None
|
||||
)
|
||||
db.add(log_entry)
|
||||
db.commit()
|
||||
logger.info(f"Email logged: {email_type} -> {recipient_emails} (status: {'sent' if success else 'failed'})")
|
||||
except Exception as e:
|
||||
db.rollback()
|
||||
logger.error(f"Failed to log email to database: {e}")
|
||||
finally:
|
||||
db.close()
|
||||
except ImportError:
|
||||
# Database not available (e.g., during testing)
|
||||
logger.warning("Could not log email - database module not available")
|
||||
|
||||
|
||||
def is_configured() -> bool:
|
||||
@ -325,7 +398,13 @@ https://nordabiznes.pl
|
||||
</html>
|
||||
"""
|
||||
|
||||
return send_email([email], subject, body_text, body_html)
|
||||
return send_email(
|
||||
to=[email],
|
||||
subject=subject,
|
||||
body_text=body_text,
|
||||
body_html=body_html,
|
||||
email_type='password_reset'
|
||||
)
|
||||
|
||||
|
||||
def send_welcome_email(email: str, name: str, verification_url: str) -> bool:
|
||||
@ -417,4 +496,11 @@ https://nordabiznes.pl
|
||||
</html>
|
||||
"""
|
||||
|
||||
return send_email([email], subject, body_text, body_html)
|
||||
return send_email(
|
||||
to=[email],
|
||||
subject=subject,
|
||||
body_text=body_text,
|
||||
body_html=body_html,
|
||||
email_type='welcome',
|
||||
recipient_name=name
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user