EmailBot/gmail_sender.py

103 lines
3.8 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.

# 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)}")