Files
replicator/app/utils/email_sender.py
2026-03-08 20:21:15 +09:00

138 lines
5.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from typing import List, Optional
from datetime import datetime
from app.core.config import settings
from app.core.logging import migration_logger
class EmailSender:
"""Класс для отправки email уведомлений"""
def __init__(self):
self.smtp_server = settings.EMAIL_HOST
self.smtp_port = settings.EMAIL_PORT
self.username = settings.EMAIL_USER
self.password = settings.EMAIL_PASSWORD
self.from_addr = settings.EMAIL_FROM
self.to_addrs = settings.EMAIL_TO
def send_email(self, subject: str, body: str, attachments: Optional[List[str]] = None) -> bool:
"""Отправка email с вложениями"""
if not all([self.smtp_server, self.username, self.password, self.from_addr]):
migration_logger.warning("Настройки email не заполнены. Отправка email пропущена.")
return False
try:
# Создаем сообщение
msg = MIMEMultipart()
msg['From'] = self.from_addr
msg['To'] = ', '.join(self.to_addrs)
msg['Subject'] = subject
msg['Date'] = datetime.now().strftime('%a, %d %b %Y %H:%M:%S %z')
# Добавляем текст
msg.attach(MIMEText(body, 'plain', 'utf-8'))
# Добавляем вложения
if attachments:
for file_path in attachments:
try:
with open(file_path, 'rb') as f:
part = MIMEApplication(f.read(), Name=file_path.split('/')[-1])
part['Content-Disposition'] = f'attachment; filename="{file_path.split("/")[-1]}"'
msg.attach(part)
except Exception as e:
migration_logger.error(f"Ошибка при добавлении вложения {file_path}: {e}")
# Отправляем
with smtplib.SMTP_SSL(self.smtp_server, self.smtp_port) as server:
server.login(self.username, self.password)
server.send_message(msg)
migration_logger.info(f"Email успешно отправлен на {', '.join(self.to_addrs)}")
return True
except Exception as e:
migration_logger.error(f"Ошибка при отправке email: {e}")
return False
def send_error_notification(self, error_message: str, traceback_str: str = None, table_name: str = None):
"""Отправить уведомление об ошибке"""
subject = f"ОШИБКА МИГРАЦИИ - {datetime.now().strftime('%Y-%m-%d %H:%M')}"
body = f"""
🚨 ОШИБКА В ПРОЦЕССЕ МИГРАЦИИ ДАННЫХ
{'='*60}
Время: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
Сервис: Migration Service
"""
if table_name:
body += f"Таблица: {table_name}\n"
body += f"""
Ошибка:
{error_message}
"""
if traceback_str:
body += f"""
📎 Детали:
{traceback_str}
"""
body += """
🔧 Необходимо проверить логи и устранить проблему.
"""
return self.send_email(subject, body)
def send_success_notification(self, stats: dict, duration: float):
"""Отправить уведомление об успешной миграции"""
subject = f"УСПЕШНАЯ МИГРАЦИЯ - {datetime.now().strftime('%Y-%m-%d %H:%M')}"
body = f"""
МИГРАЦИЯ ДАННЫХ УСПЕШНО ЗАВЕРШЕНА
{'='*60}
Время: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
Длительность: {duration:.1f} сек
СТАТИСТИКА:
{'='*40}
Всего строк в БД: {stats.get('total_rows', 0)}
Таблиц обработано: {stats.get('total_tables', 0)}
Последняя репликация: {stats.get('last_replication', 'Нет данных')}
Миграция выполнена успешно!
"""
return self.send_email(subject, body)
def send_start_notification(self, tables: List[str], full_reload: bool):
"""Отправить уведомление о начале миграции"""
subject = f"НАЧАЛО МИГРАЦИИ - {datetime.now().strftime('%Y-%m-%d %H:%M')}"
body = f"""
НАЧАЛО МИГРАЦИИ ДАННЫХ
{'='*60}
Время старта: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
Режим: {'ПОЛНАЯ ПЕРЕЗАГРУЗКА' if full_reload else 'ИНКРЕМЕНТАЛЬНАЯ'}
Таблиц для обработки: {len(tables)}
СПИСОК ТАБЛИЦ:
{chr(10).join([f'{t}' for t in tables])}
Миграция запущена...
"""
return self.send_email(subject, body)
email_sender = EmailSender()