Skip to content

Commit c8697a4

Browse files
anduimaguiclaude
andcommitted
Fix email service startup errors - lazy initialization and graceful fallback
- Move email service creation from module level to endpoint level - Handle missing credentials gracefully with warnings instead of errors - Add configuration checks in email service methods - Prevent startup failures due to missing CLIENT_SECRET env var 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b0af730 commit c8697a4

5 files changed

Lines changed: 34 additions & 10 deletions

File tree

scripts/test_direct_email.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ async def test_direct_email(to_email: str) -> None:
102102
<ul>
103103
<li>From Email: {from_email}</li>
104104
<li>To Email: {to_email}</li>
105-
<li>Tenant ID: {os.getenv('AZURE_TENANT_ID')}</li>
105+
<li>Tenant ID: {os.getenv('TENANT_ID')}</li>
106106
</ul>
107107
</div>
108108

scripts/test_user_auth_email.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ async def test_email(to_email: str) -> None:
9999
<li>From Email: {os.getenv('MS_FROM_EMAIL')}</li>
100100
<li>User Email: {os.getenv('USER_EMAIL')}</li>
101101
<li>To Email: {to_email}</li>
102-
<li>Tenant ID: {os.getenv('AZURE_TENANT_ID')}</li>
102+
<li>Tenant ID: {os.getenv('TENANT_ID')}</li>
103103
</ul>
104104
</div>
105105

src/routers/email.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,18 @@ class DigestRequest(BaseModel):
3333
limit: int | None = None
3434
test: bool = False
3535

36-
# Initialize email service
37-
email_service = create_email_service()
36+
# Lazy email service initialization
37+
def get_email_service():
38+
"""Get email service instance. Created on first use to avoid startup errors."""
39+
return create_email_service()
3840

3941
@router.post("/send", dependencies=[Depends(require_admin)])
4042
async def send_email(request: EmailRequest):
4143
"""
4244
Send an email to multiple recipients.
4345
Only accessible by admin users.
4446
"""
47+
email_service = get_email_service()
4548
success = await email_service.send_email(
4649
to_emails=request.to_emails,
4750
subject=request.subject,
@@ -60,6 +63,7 @@ async def send_notification(request: NotificationRequest):
6063
Send a templated notification email.
6164
Only accessible by admin users.
6265
"""
66+
email_service = get_email_service()
6367
success = await email_service.send_notification_email(
6468
to_email=request.to_email,
6569
subject=request.subject,

src/services/graph_direct_auth.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,25 @@ class GraphDirectAuth:
1818
def __init__(self):
1919
self.token = None
2020
self.token_expires = 0
21-
self.tenant_id = os.getenv('AZURE_TENANT_ID')
22-
self.client_id = os.getenv('AZURE_CLIENT_ID')
23-
self.client_secret = os.getenv('AZURE_CLIENT_SECRET')
21+
self.tenant_id = os.getenv('TENANT_ID')
22+
self.client_id = os.getenv('CLIENT_ID')
23+
self.client_secret = os.getenv('CLIENT_SECRET')
2424

2525
if not all([self.tenant_id, self.client_id, self.client_secret]):
26-
raise ValueError("Missing required environment variables for Graph authentication")
26+
logger.warning("Missing required environment variables for Graph authentication. Service will not be available.")
27+
self.configured = False
28+
return
29+
30+
self.configured = True
2731

2832
self.token_url = f"https://login.microsoftonline.com/{self.tenant_id}/oauth2/v2.0/token"
2933
self.graph_url = "https://graph.microsoft.com/v1.0"
3034

3135
async def ensure_token(self) -> str:
3236
"""Ensure we have a valid token, refreshing if necessary"""
37+
if not getattr(self, 'configured', False):
38+
raise ValueError("GraphDirectAuth not properly configured - missing environment variables")
39+
3340
current_time = asyncio.get_event_loop().time()
3441

3542
# If token is expired or will expire in the next 5 minutes, refresh it

src/services/msgraph_service.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,9 @@ def __init__(self, useUserAccessToken: bool = False):
3636
self.from_email = os.getenv('MS_FROM_EMAIL')
3737
logger.info(f"MSGraphEmailService config: TENANT_ID={tenant_id}, CLIENT_ID={client_id}, FROM_EMAIL={self.from_email}, EMAIL_SERVICE_TYPE={service_type}")
3838
if not all([tenant_id, client_id, client_secret]):
39-
logger.error("Missing required environment variables for authentication")
40-
raise ValueError("TENANT_ID, CLIENT_ID, and CLIENT_SECRET must be set")
39+
logger.warning("Missing required environment variables for MSGraph authentication. Service will not be available.")
40+
self.credential = None
41+
return
4142

4243
# Use ClientSecretCredential for app authentication
4344
self.credential = ClientSecretCredential(
@@ -72,6 +73,12 @@ async def send_email(
7273
content_type=content_type,
7374
useUserAccessToken=True
7475
)
76+
77+
# Check if service is properly configured
78+
if not hasattr(self, 'credential') or self.credential is None:
79+
logger.error("MSGraphEmailService not properly configured - missing credentials")
80+
return False
81+
7582
"""Send an email using Microsoft Graph API with Mail.Send permission"""
7683
try:
7784
logger.info(f"send_email config: TENANT_ID={os.getenv('TENANT_ID')}, CLIENT_ID={os.getenv('CLIENT_ID')}, FROM_EMAIL={self.from_email}, EMAIL_SERVICE_TYPE={os.getenv('EMAIL_SERVICE_TYPE')}, to_emails={to_emails}, subject={subject}")
@@ -149,6 +156,12 @@ async def send_notification_email(
149156
dynamic_data=dynamic_data,
150157
useUserAccessToken=True
151158
)
159+
160+
# Check if service is properly configured
161+
if not hasattr(self, 'credential') or self.credential is None:
162+
logger.error("MSGraphEmailService not properly configured - missing credentials")
163+
return False
164+
152165
"""Send a templated notification email using Microsoft Graph API"""
153166
try:
154167
logger.info(f"Preparing to send notification email to {to_email}")

0 commit comments

Comments
 (0)