Доработка VK-бота ИКП: контент, новые функции, защита и визуал
Контент и брендинг: - Реальные данные ИК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>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
"""Отправка 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
|
||||
Reference in New Issue
Block a user