mirror of
https://gitverse.ru/kpa39l/email-assistant.git
synced 2026-09-29 09:15:09 +00:00
imap_stream (Фаза 1): IDLE-цикл с реконнектом + SQLite mailbox.db; фикс токена TG (vesti/.env всегда); фильтр актуальности urgent (>=3 дн пропуск); HERMES_REAL_HOME в imap_client
This commit is contained in:
@@ -74,11 +74,16 @@ if load_dotenv:
|
||||
load_dotenv(BASE_DIR / ".env", override=False)
|
||||
# radicale/.env — фактический источник RADICALE_PASS (проектного .env нет)
|
||||
load_dotenv(BASE_DIR / "radicale" / ".env", override=False)
|
||||
# Токен Telegram живёт в /opt/vesti/.env (проект-источник бота @dedinit_vesti).
|
||||
# Загружаем ВСЕГДА (и при наличии python-dotenv, и без него), иначе
|
||||
# VESTI_BOT_TOKEN никогда не попадает в env и все urgent-уведомления
|
||||
# падают с «Нет токена Telegram».
|
||||
vesti_env = Path("/opt/vesti/.env")
|
||||
if vesti_env.exists():
|
||||
load_dotenv(vesti_env, override=False)
|
||||
else:
|
||||
_load_env_file(BASE_DIR / ".env")
|
||||
_load_env_file(BASE_DIR / "radicale" / ".env")
|
||||
# Токен Telegram живёт в /opt/vesti/.env (проект-источник бота @dedinit_vesti);
|
||||
# опционально: если файл есть, берём VESTI_BOT_TOKEN/TELEGRAM_CHAT_ID оттуда.
|
||||
vesti_env = Path("/opt/vesti/.env")
|
||||
if vesti_env.exists():
|
||||
_load_env_file(vesti_env)
|
||||
@@ -103,6 +108,10 @@ TG_API = "https://api.telegram.org"
|
||||
LLM_TIMEOUT = 20
|
||||
MAX_PREVIEW_CHARS = 400 # превью письма для Telegram
|
||||
TG_TIMEOUT = 20
|
||||
# Письмо считается актуальным для urgent-уведомления, если оно не старше
|
||||
# этого срока (дни). Более старые НЕ шлём (пользователь просил не спамить
|
||||
# устаревшими срочными), но помечаем handled_urgent, чтобы не перебирать.
|
||||
URGENT_MAX_AGE_DAYS = 3
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -409,6 +418,29 @@ def format_date_for_tg(date_str):
|
||||
return s
|
||||
|
||||
|
||||
def is_urgent_recent(headers):
|
||||
"""Актуально ли письмо для urgent-уведомления (не старше URGENT_MAX_AGE_DAYS).
|
||||
|
||||
Сравнивает дату письма (frontmatter date / internal_date) с текущей.
|
||||
Если дату не удалось распарсить — считаем актуальным (бить тревогу лучше,
|
||||
чем молчать). Возвращает bool.
|
||||
"""
|
||||
from datetime import datetime, timedelta
|
||||
s = (headers.get("date") or headers.get("internal_date") or "").strip()
|
||||
if not s:
|
||||
return True # нет даты — не фильтруем
|
||||
# форматы: '2026-09-02 10:49+03:00' | '2026-09-02T10:49:03+03:00'
|
||||
m = re.match(r"^(\d{4})-(\d{2})-(\d{2})", s)
|
||||
if not m:
|
||||
return True
|
||||
try:
|
||||
d = datetime(int(m.group(1)), int(m.group(2)), int(m.group(3)))
|
||||
except ValueError:
|
||||
return True
|
||||
limit = datetime.now() - timedelta(days=URGENT_MAX_AGE_DAYS)
|
||||
return d >= limit
|
||||
|
||||
|
||||
def handle_urgent(path, headers, body):
|
||||
"""Отправить уведомление в Telegram. Возвращает (ok, detail)."""
|
||||
subject = (headers.get("subject") or "(без темы)").strip()
|
||||
@@ -416,6 +448,11 @@ def handle_urgent(path, headers, body):
|
||||
# Дата/время получения — из frontmatter, формат ДД.ММ.ГГГГ ЧЧ:ММ
|
||||
date = format_date_for_tg(headers.get("date") or headers.get("internal_date"))
|
||||
date_line = f"📅 {date}\n" if date else ""
|
||||
|
||||
# ФИЛЬТР АКТУАЛЬНОСТИ: старые письма не шлём (см. URGENT_MAX_AGE_DAYS).
|
||||
if not is_urgent_recent(headers):
|
||||
return True, f"пропущено: письмо старше {URGENT_MAX_AGE_DAYS} дн (актуальность истекла)"
|
||||
|
||||
preview = body.strip()
|
||||
if len(preview) > MAX_PREVIEW_CHARS:
|
||||
preview = preview[:MAX_PREVIEW_CHARS].rstrip() + "…"
|
||||
|
||||
Reference in New Issue
Block a user