Implement real SMTP delivery and transactional email auth flow
All checks were successful
CI / test (push) Successful in 21s
All checks were successful
CI / test (push) Successful in 21s
Email delivery: - Replaced logging-only email sender with aiosmtplib SMTP implementation. - Added provider mode switch via EMAIL_PROVIDER (log/smtp). - Added TLS/SSL and timeout controls for SMTP transport. Auth registration flow: - Made register/resend/reset email flows transactional with rollback on delivery failure. - Return 503 when verification/reset email cannot be delivered. Configuration: - Extended settings and env templates for EMAIL_PROVIDER, SMTP_USE_SSL, SMTP_TIMEOUT_SECONDS. - Updated docker-compose environment mapping for new SMTP variables.
This commit is contained in:
@@ -19,7 +19,7 @@ from app.auth.schemas import (
|
||||
)
|
||||
from app.config.settings import settings
|
||||
from app.database.session import get_db
|
||||
from app.email.service import EmailService, get_email_service
|
||||
from app.email.service import EmailDeliveryError, EmailService, get_email_service
|
||||
from app.users.models import User
|
||||
from app.users.repository import create_user, get_user_by_email, get_user_by_id, get_user_by_username
|
||||
from app.utils.security import (
|
||||
@@ -62,10 +62,13 @@ async def register_user(
|
||||
expires_at = datetime.now(timezone.utc) + timedelta(hours=settings.email_verification_token_expire_hours)
|
||||
await auth_repository.delete_email_verification_tokens_for_user(db, user.id)
|
||||
await auth_repository.create_email_verification_token(db, user.id, verification_token, expires_at)
|
||||
try:
|
||||
await email_service.send_verification_email(payload.email, verification_token)
|
||||
except EmailDeliveryError as exc:
|
||||
await db.rollback()
|
||||
raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unable to send verification email") from exc
|
||||
await db.commit()
|
||||
|
||||
await email_service.send_verification_email(payload.email, verification_token)
|
||||
|
||||
|
||||
async def verify_email(db: AsyncSession, payload: VerifyEmailRequest) -> None:
|
||||
record = await auth_repository.get_email_verification_token(db, payload.token)
|
||||
@@ -99,10 +102,13 @@ async def resend_verification_email(
|
||||
expires_at = datetime.now(timezone.utc) + timedelta(hours=settings.email_verification_token_expire_hours)
|
||||
await auth_repository.delete_email_verification_tokens_for_user(db, user.id)
|
||||
await auth_repository.create_email_verification_token(db, user.id, verification_token, expires_at)
|
||||
try:
|
||||
await email_service.send_verification_email(user.email, verification_token)
|
||||
except EmailDeliveryError as exc:
|
||||
await db.rollback()
|
||||
raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unable to send verification email") from exc
|
||||
await db.commit()
|
||||
|
||||
await email_service.send_verification_email(user.email, verification_token)
|
||||
|
||||
|
||||
async def login_user(db: AsyncSession, payload: LoginRequest) -> TokenResponse:
|
||||
user = await get_user_by_email(db, payload.email)
|
||||
@@ -168,10 +174,13 @@ async def request_password_reset(
|
||||
expires_at = datetime.now(timezone.utc) + timedelta(hours=settings.password_reset_token_expire_hours)
|
||||
await auth_repository.delete_password_reset_tokens_for_user(db, user.id)
|
||||
await auth_repository.create_password_reset_token(db, user.id, reset_token, expires_at)
|
||||
try:
|
||||
await email_service.send_password_reset_email(user.email, reset_token)
|
||||
except EmailDeliveryError as exc:
|
||||
await db.rollback()
|
||||
raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail="Unable to send reset email") from exc
|
||||
await db.commit()
|
||||
|
||||
await email_service.send_password_reset_email(user.email, reset_token)
|
||||
|
||||
|
||||
async def reset_password(db: AsyncSession, payload: ResetPasswordRequest) -> None:
|
||||
record = await auth_repository.get_password_reset_token(db, payload.token)
|
||||
|
||||
Reference in New Issue
Block a user