Emails : robustesse SMTP + diagnostic
- config.py : retrait des identifiants OVH réels remis en dur ; défauts neutres (email_enabled=false). Les vraies valeurs vont dans .env. - open_smtp : le port 465 force le SSL implicite (SMTPS) même si SMTP_SSL=false — c'était la cause des envois qui ne partaient pas (connexion en clair sur un port TLS -> timeout). - deliver_many : les erreurs de connexion / auth / rejet sont journalisées avec le message du serveur et ne remontent plus (l'appel HTTP n'échoue pas). - Lien magique : envoi en tâche de fond (BackgroundTasks) comme les notifications ; ne bloque plus la réponse. - app/email/check.py : `python -m app.email.check <destinataire>` — affiche la config effective et envoie un email de test, avec la cause exacte en cas d'échec. - Tests : fixture autouse forçant EMAIL_ENABLED=false (aucun test ne touche un vrai SMTP, quel que soit le .env local) ; test_full_flow lit l'email capturé au lieu des logs. 137 tests OK. - .env.example : notes port 465 / From = boîte authentifiée / commande check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
6b08dcc953
commit
b84f62dfab
@@ -10,7 +10,7 @@ Deux systèmes, selon le compte :
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status
|
||||
from sqlalchemy import func
|
||||
from sqlmodel import Session, select
|
||||
|
||||
@@ -125,10 +125,12 @@ def change_password(
|
||||
def request_magic_link(
|
||||
edition_id: uuid.UUID,
|
||||
payload: MagicLinkRequest,
|
||||
background: BackgroundTasks,
|
||||
session: Session = Depends(get_session),
|
||||
) -> dict[str, str]:
|
||||
"""Émet un lien magique si un compte **sans mot de passe** correspond.
|
||||
Réponse identique dans tous les cas (pas de divulgation)."""
|
||||
Réponse identique dans tous les cas (pas de divulgation). L'email part en
|
||||
tâche de fond (une erreur SMTP est journalisée, pas remontée)."""
|
||||
account = _account_by_email(session, edition_id, payload.email)
|
||||
if account is not None and account.password_hash is None:
|
||||
settings = get_settings()
|
||||
@@ -138,7 +140,7 @@ def request_magic_link(
|
||||
link=build_magic_link_url(raw),
|
||||
minutes=settings.magic_link_ttl_minutes,
|
||||
)
|
||||
send(account.email, subject, body)
|
||||
background.add_task(send, account.email, subject, body)
|
||||
if not settings.email_enabled:
|
||||
# Aide au dev sans SMTP : le jeton (non nominatif) est journalisé.
|
||||
logger.info(
|
||||
|
||||
Reference in New Issue
Block a user