Files
dify/api/services/human_input_v2/email_otp_composition.py
T
4293584598 ci: bump type checker (#44015)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Codex <codex@openai.com>
2026-10-30 11:22:51 +00:00

40 lines
1.5 KiB
Python

"""Deployment mail and shared Redis composition for public email proof."""
import logging
from smtplib import SMTPException
from python_http_client.exceptions import HTTPError
from resend.exceptions import ResendError
from core.db.session_factory import session_factory
from extensions.ext_mail import mail
from extensions.ext_redis import redis_client
from libs.helper import RateLimiter
from services.human_input_v2.email_otp_service import EmailOtpError, EmailOtpService, OtpFailure, OtpMail
logger = logging.getLogger(__name__)
_OTP_TEMPLATE = """<p>Use this verification code to submit your approval form:</p>
<p><strong>{code}</strong></p><p>This code expires in 10 minutes.</p>"""
def _send(email: str, otp: str) -> None:
# Provider exceptions may contain secrets; expose only the OTP failure code.
try:
mail.send(
to=email,
subject="Verify your approval form submission",
html=_OTP_TEMPLATE.format(code=otp),
)
except (SMTPException, OSError, HTTPError, ResendError, ValueError):
logger.warning("Human Input OTP mail delivery failed")
raise EmailOtpError(OtpFailure.DELIVERY) from None
def build_email_otp_service() -> EmailOtpService:
return EmailOtpService(
session_factory=session_factory.create_session,
redis=redis_client,
limiter=RateLimiter(prefix="hitl:otp:sends", max_attempts=5, time_window=3600),
mail=OtpMail(available=mail.is_inited, send=_send),
)