"""Отправка email уведомлений через SMTP.""" import logging import smtplib import ssl from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from app.config import settings logger = logging.getLogger(__name__) TASK_TYPE_SUBJECTS = { "search": "Источники найдены — Академический помощник", "plagiarism": "Проверка плагиата завершена — Академический помощник", "summarize": "Краткое изложение готово — Академический помощник", "gost": "Библиография отформатирована — Академический помощник", } class EmailSender: """Отправщик email уведомлений.""" def _send(self, to_email: str, subject: str, html_body: str) -> None: """ Отправить email через SMTP SSL. Args: to_email: Email получателя subject: Тема письма html_body: HTML тело письма """ msg = MIMEMultipart("alternative") msg["Subject"] = subject msg["From"] = settings.SMTP_FROM msg["To"] = to_email msg.attach(MIMEText(html_body, "html", "utf-8")) try: tls_ctx = ssl.create_default_context() if not settings.SMTP_TLS_VERIFY: tls_ctx.check_hostname = False tls_ctx.verify_mode = ssl.CERT_NONE if settings.SMTP_PORT == 465: with smtplib.SMTP_SSL(settings.SMTP_HOST, settings.SMTP_PORT, context=tls_ctx) as smtp: smtp.login(settings.SMTP_USER, settings.SMTP_PASSWORD) smtp.send_message(msg) else: with smtplib.SMTP(settings.SMTP_HOST, settings.SMTP_PORT) as smtp: smtp.ehlo() smtp.starttls(context=tls_ctx) smtp.ehlo() smtp.login(settings.SMTP_USER, settings.SMTP_PASSWORD) smtp.send_message(msg) logger.info(f"Email отправлен: {to_email!r}, тема: {subject!r}") except smtplib.SMTPException as e: logger.error(f"SMTP ошибка при отправке письма на {to_email!r}: {e}") raise def send_task_done( self, user_email: str, user_name: str, task_id: str, task_type: str, summary: str, app_url: str, ) -> None: """ Отправить уведомление о завершении задачи. Args: user_email: Email пользователя user_name: Имя пользователя task_id: ID завершённой задачи task_type: Тип задачи (search, plagiarism, и т.д.) summary: Краткое описание результата app_url: Базовый URL приложения """ subject = TASK_TYPE_SUBJECTS.get(task_type, "Задача выполнена — Академический помощник") task_url = f"{app_url}/tasks/{task_id}" html_body = f"""

Академический помощник

academic.jze9.ru

Здравствуйте, {user_name}!

{summary}

Открыть результат →

Академический помощник · academic.jze9.ru
Это автоматическое письмо, не нужно отвечать на него.

""" self._send(user_email, subject, html_body) def send_verification(self, user_email: str, user_name: str, token: str, app_url: str) -> None: """ Отправить письмо для верификации email. Args: user_email: Email для верификации user_name: Имя пользователя token: Токен верификации app_url: Базовый URL приложения """ verify_url = f"{app_url}/verify-email/{token}" subject = "Подтвердите email — Академический помощник" html_body = f"""

Подтвердите ваш email

Здравствуйте, {user_name}!

Нажмите кнопку ниже, чтобы подтвердить ваш email и активировать аккаунт.

Подтвердить email →

Ссылка действительна 48 часов. Если вы не регистрировались, проигнорируйте это письмо.

""" self._send(user_email, subject, html_body)