diff --git a/backend/app/routers/applications.py b/backend/app/routers/applications.py index 4dfe4a6..35a3f09 100644 --- a/backend/app/routers/applications.py +++ b/backend/app/routers/applications.py @@ -190,9 +190,11 @@ def send_contract(index: int, request: SendContractRequest): candidate_name=application.name, ) except email_service.EmailNotConfiguredError as exc: - raise HTTPException(status_code=503, detail=str(exc)) from exc + raise HTTPException(status_code=409, detail=str(exc)) from exc except email_service.EmailSendError as exc: - raise HTTPException(status_code=502, detail=str(exc)) from exc + # 424 (not 502): a CDN in front of the API rewrites upstream 5xx into its + # own error page, which would hide the reason from the coordinator. + raise HTTPException(status_code=424, detail=str(exc)) from exc application.contract_sent_to = request.to application.contract_sent_at = datetime.now(timezone.utc).isoformat() diff --git a/backend/app/services/email_service.py b/backend/app/services/email_service.py index 979c28e..931e1f2 100644 --- a/backend/app/services/email_service.py +++ b/backend/app/services/email_service.py @@ -73,10 +73,16 @@ def send_signed_contract( ) response.raise_for_status() except httpx.HTTPStatusError as exc: - raise EmailSendError( + message = ( f"n8n webhook returned {exc.response.status_code}: {exc.response.text[:200]}" - ) from exc + ) + logger.error("Contract email failed — %s", message) + raise EmailSendError(message) from exc except httpx.HTTPError as exc: - raise EmailSendError(f"Could not reach the n8n webhook: {exc}") from exc + # Log the exception type too: a bare message like "" is common for + # connect/DNS errors and tells the operator nothing on its own. + message = f"Could not reach the n8n webhook ({type(exc).__name__}): {exc}" + logger.error("Contract email failed — %s", message) + raise EmailSendError(message) from exc logger.info("Signed contract emailed via n8n to %s", to)