79cc1ba38d
Контент и брендинг: - Реальные данные ИКP (infocyber.pro): услуги CS2/Dota 2/WoT, цены, FAQ, контакты, площадки - Приветствие и тексты приведены к бренду ИКП Новые функции: - Раздельные согласия (152-ФЗ): маркетинговая рассылка — отдельный необязательный шаг - Шаг «удобное время звонка» в форме заявки - Раздел «Карьера в ИКП»: набор игроков и сотрудников (таблица applications) - Админ-команды: статистика (стата) и рассылка по подписчикам с троттлингом и отпиской - Журнал заявок leads, «бот помнит клиента», международные телефоны, валидация имени - Email-уведомления о заявках и откликах (mailer.py); HR-адрес через HR_MAIL_TO Защита: - Анти-флуд по пользователю и кулдаун уведомлений оператору (анти-DDoS) - Веб-форма: серверная валидация, honeypot, рейт-лимит, CORS по ALLOWED_ORIGIN, SQLite-first Визуал: - Убрана Markdown-разметка (VK её не рендерит) - Логотип в приветствии, карусели услуг и «Карьеры» (фото 13:8), предзагрузка медиа - Кнопки-ссылки на соцсети - Веб-форма: анимации, конфетти на успехе Промокоды добавлены, но пока ВЫКЛЮЧЕНЫ флагом PROMO_ENABLED (по умолчанию false). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
62 lines
2.5 KiB
Python
62 lines
2.5 KiB
Python
"""Отправка email-уведомлений о заявках на корпоративную почту.
|
|
|
|
Доступы берутся из .env (см. .env.example). Если SMTP не настроен,
|
|
функция тихо пропускает отправку и возвращает False, не ломая основной поток.
|
|
"""
|
|
import smtplib
|
|
import logging
|
|
from typing import Optional
|
|
from email.mime.text import MIMEText
|
|
from email.header import Header
|
|
from email.utils import formataddr
|
|
|
|
import config
|
|
|
|
logger = logging.getLogger("VK_Bot_IKP.mailer")
|
|
|
|
|
|
def is_configured() -> bool:
|
|
"""Проверяет, заданы ли минимальные параметры SMTP для отправки писем."""
|
|
return bool(
|
|
getattr(config, "SMTP_HOST", "")
|
|
and getattr(config, "SMTP_USER", "")
|
|
and getattr(config, "SMTP_PASSWORD", "")
|
|
and getattr(config, "MAIL_TO", "")
|
|
)
|
|
|
|
|
|
def send_email(subject: str, body: str, mail_to: Optional[str] = None) -> bool:
|
|
"""Отправляет письмо. По умолчанию на config.MAIL_TO; можно указать другой адрес (например, HR)."""
|
|
if not is_configured():
|
|
logger.info("[MAIL] Пропущено: SMTP не настроен в .env (SMTP_HOST/SMTP_USER/SMTP_PASSWORD/MAIL_TO).")
|
|
return False
|
|
|
|
host = config.SMTP_HOST
|
|
port = int(getattr(config, "SMTP_PORT", 465))
|
|
user = config.SMTP_USER
|
|
password = config.SMTP_PASSWORD
|
|
mail_from = getattr(config, "MAIL_FROM", "") or user
|
|
mail_to = mail_to or config.MAIL_TO
|
|
use_ssl = bool(getattr(config, "SMTP_USE_SSL", True))
|
|
|
|
msg = MIMEText(body, "plain", "utf-8")
|
|
msg["Subject"] = Header(subject, "utf-8")
|
|
msg["From"] = formataddr((str(Header("Бот ИКП", "utf-8")), mail_from))
|
|
msg["To"] = mail_to
|
|
|
|
try:
|
|
if use_ssl:
|
|
with smtplib.SMTP_SSL(host, port, timeout=15) as server:
|
|
server.login(user, password)
|
|
server.sendmail(mail_from, [a.strip() for a in mail_to.split(",")], msg.as_string())
|
|
else:
|
|
with smtplib.SMTP(host, port, timeout=15) as server:
|
|
server.starttls()
|
|
server.login(user, password)
|
|
server.sendmail(mail_from, [a.strip() for a in mail_to.split(",")], msg.as_string())
|
|
logger.info(f"[MAIL] Письмо отправлено на {mail_to}: {subject}")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"[MAIL] Ошибка отправки письма: {e}")
|
|
return False
|