From 39a376b39bcb8e9d3f940eaecbe58e100d27418b Mon Sep 17 00:00:00 2001 From: poduck Date: Wed, 3 Dec 2025 15:19:46 -0500 Subject: [PATCH] fix(email): Add SMTP configuration and fix invitation link routing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add SMTP email backend support to production settings (EMAIL_HOST, EMAIL_PORT, etc.) - Falls back to console backend if SMTP not configured - Fix AcceptInvitePage to support both path parameter (/accept-invite/:token) and query parameter (?token=...) formats for invitation tokens - Add route for /accept-invite/:token in App.tsx 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- frontend/src/App.tsx | 2 ++ frontend/src/pages/AcceptInvitePage.tsx | 6 ++++-- smoothschedule/config/settings/production.py | 17 +++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 1adecd5..4509fda 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -279,6 +279,7 @@ const AppContent: React.FC = () => { } /> } /> } /> + } /> } /> } /> @@ -322,6 +323,7 @@ const AppContent: React.FC = () => { } /> } /> } /> + } /> } /> } /> diff --git a/frontend/src/pages/AcceptInvitePage.tsx b/frontend/src/pages/AcceptInvitePage.tsx index 36b0b4b..88bb907 100644 --- a/frontend/src/pages/AcceptInvitePage.tsx +++ b/frontend/src/pages/AcceptInvitePage.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { useSearchParams, useNavigate } from 'react-router-dom'; +import { useSearchParams, useNavigate, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { useInvitationDetails, @@ -23,8 +23,10 @@ import { const AcceptInvitePage: React.FC = () => { const { t } = useTranslation(); const [searchParams] = useSearchParams(); + const { token: pathToken } = useParams<{ token: string }>(); const navigate = useNavigate(); - const token = searchParams.get('token'); + // Support both path parameter (/accept-invite/:token) and query parameter (?token=...) + const token = pathToken || searchParams.get('token'); const { data: invitation, isLoading, error } = useInvitationDetails(token); const acceptInvitationMutation = useAcceptInvitation(); diff --git a/smoothschedule/config/settings/production.py b/smoothschedule/config/settings/production.py index a7cc5fb..b1f6a43 100644 --- a/smoothschedule/config/settings/production.py +++ b/smoothschedule/config/settings/production.py @@ -168,10 +168,19 @@ if MAILGUN_API_KEY and MAILGUN_DOMAIN: } else: # Fall back to SMTP or console email - EMAIL_BACKEND = env( - "DJANGO_EMAIL_BACKEND", - default="django.core.mail.backends.console.EmailBackend" - ) + EMAIL_HOST = env("EMAIL_HOST", default="") + EMAIL_PORT = env.int("EMAIL_PORT", default=587) + EMAIL_HOST_USER = env("EMAIL_HOST_USER", default="") + EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD", default="") + EMAIL_USE_TLS = env.bool("EMAIL_USE_TLS", default=True) + + if EMAIL_HOST and EMAIL_HOST_USER and EMAIL_HOST_PASSWORD: + EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" + else: + EMAIL_BACKEND = env( + "DJANGO_EMAIL_BACKEND", + default="django.core.mail.backends.console.EmailBackend" + ) # LOGGING