# gmail_sender.py import os import pickle import base64 from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.mime.image import MIMEImage from email.mime.application import MIMEApplication from typing import List from queue_manager import QueuedFile from timezone_utils import format_time import logging import mimetypes logger = logging.getLogger(__name__) # Пути к файлам аутентификации CREDENTIALS_FILE = 'credentials.json' # если нужен для обновления токена TOKEN_FILE = 'token.pickle' SCOPES = ['https://www.googleapis.com/auth/gmail.send'] def get_gmail_service(): """Загружает сохранённый токен и возвращает сервис Gmail API""" creds = None if not os.path.exists(TOKEN_FILE): raise Exception(f"Файл {TOKEN_FILE} не найден. Загрузи его на сервер.") with open(TOKEN_FILE, 'rb') as token: creds = pickle.load(token) # Если токен протух — обновляем (потребуется credentials.json) from google.auth.transport.requests import Request if creds and creds.expired and creds.refresh_token: creds.refresh(Request()) # Сохраняем обновлённый токен with open(TOKEN_FILE, 'wb') as token: pickle.dump(creds, token) from googleapiclient.discovery import build return build('gmail', 'v1', credentials=creds) async def send_batch_to_email(target_email: str, files: List[QueuedFile]): """Отправка письма через Gmail API (без SMTP)""" if not target_email: raise ValueError("Целевая почта не настроена") if not files: return # Создаём письмо msg = MIMEMultipart() msg['To'] = target_email msg['From'] = 'me' # 'me' = авторизованный аккаунт msg['Subject'] = f"📎 {len(files)} новых файлов" # Текст письма body = f"Получено {len(files)} файлов.\n\n" body += "Список вложений:\n" body += "-" * 30 + "\n" for idx, file in enumerate(files, 1): file_size_kb = len(file.file_bytes) / 1024 if file_size_kb > 1024: size_str = f"{file_size_kb / 1024:.2f} MB" else: size_str = f"{file_size_kb:.2f} KB" body += f"{idx}. {file.filename} ({size_str})\n" body += "\n---\n" body += f"Время отправки: {format_time(files[0].timestamp)}" msg.attach(MIMEText(body, 'plain')) # Добавляем вложения for file in files: try: mime_type, encoding = mimetypes.guess_type(file.filename) if mime_type and mime_type.startswith('image/'): img_type = mime_type.split('/')[1] mime_file = MIMEImage(file.file_bytes, _subtype=img_type) else: mime_file = MIMEApplication(file.file_bytes, _subtype='octet-stream') mime_file.add_header('Content-Disposition', 'attachment', filename=file.filename) msg.attach(mime_file) except Exception as e: logger.error(f"Ошибка при добавлении вложения {file.filename}: {e}") # Кодируем в base64 для API raw_message = base64.urlsafe_b64encode(msg.as_bytes()).decode() body_message = {'raw': raw_message} # Отправляем через Gmail API try: service = get_gmail_service() result = service.users().messages().send(userId='me', body=body_message).execute() logger.info(f"✅ Письмо отправлено через Gmail API, ID: {result['id']}") except Exception as e: raise Exception(f"Gmail API ошибка: {str(e)}")