Skip to content

Redesign email templates with dark theme#443

Open
beng360 wants to merge 7 commits into
mainfrom
feat/email-templates-redesign
Open

Redesign email templates with dark theme#443
beng360 wants to merge 7 commits into
mainfrom
feat/email-templates-redesign

Conversation

@beng360
Copy link
Copy Markdown
Contributor

@beng360 beng360 commented May 23, 2026

Summary

  • Complete redesign of all email notification templates with a sleek dark theme (#0a0a0a bg, #141414 card, color-coded accent bars)
  • Adds send_action_completed_email template (success/failure variants with error details)
  • All links redirect to aurora-ai.net
  • 4 template types: Investigation Started, RCA Complete, Email Verification, Action Completed

Test plan

  • Sent all templates to inbox and verified rendering
  • Verify templates render correctly in Gmail, Outlook, Apple Mail
  • Confirm links resolve to aurora-ai.net

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added "Action Completed/Failed" email with duration, status indicator, optional error details, and session-based CTA.
    • Updated "Investigation started" and "Investigation completed" notifications and verification emails with refreshed wording and CTAs.
  • Style

    • Redesigned notification emails to a dark theme with updated severity color accents.
  • Improvements

    • Improved duration/timestamp formatting, summary truncation, safer escaping of user content, and a default sender name when unset.
  • Documentation

    • New email notifications docs: setup, required variables, provider guidance, supported types, and enablement instructions.

Review Change Stack

…mplate

Replace the white-background email templates with a modern dark theme design
(#0a0a0a background, #141414 card, accent color bars). All 4 template types:
- Investigation Started: red accent, severity badge, analysis status indicator
- Investigation Completed: green accent, RCA summary box, resolution metrics
- Email Verification: purple accent, monospace code display
- Action Completed: green/red accent based on success/failure, error details

All links point to aurora-ai.net. Removes old helper methods (_email_header_html,
_cta_button_html, etc.) in favor of a single _base_html shell.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 23, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Refactors EmailService to produce dark-themed HTML emails, consolidates severity/color and timestamp/URL helpers, simplifies SMTP multipart assembly, rewrites investigation/verification emails with escaping, adds EmailService.send_action_completed_email, and adds docs for SMTP and notification setup.

Changes

Email Service Dark Theme & Action Notifications

Layer / File(s) Summary
Service Configuration & SMTP send
server/utils/notifications/email_service.py
Module initialization updated; EmailService defaults SMTP_FROM_NAME to "Aurora SRE", validates SMTP env vars, replaces previous severity scheme with solid severity color presets and _get_severity_color(), and simplifies _send_email to build multipart/alternative with plain-text and HTML parts.
HTML helpers and theming
server/utils/notifications/email_service.py
Adds helpers for severity lookup, timestamp formatting, incident URL construction, and _base_html(...) dark-themed email wrapper used by notification builders.
Investigation Started Email
server/utils/notifications/email_service.py
send_investigation_started_email derives incident fields, computes formatted timestamp and severity color, escapes user-controlled values and URLs (quoting where appropriate), builds plain-text content and a dark HTML body via _base_html(), and sends via _send_email().
Investigation Completed, Verification & Action Completed (core)
server/utils/notifications/email_service.py
send_investigation_completed_email now renders minute-granularity duration and truncates aurora_summary to 600 chars before escaping; send_verification_code_email rewritten with new copy and dark HTML layout. Core of send_action_completed_email implemented: duration calc, success/failure label/icon/color mapping, optional session CTA URL, and escaping of action/session values.
Action completion finalization & docs
server/utils/notifications/email_service.py, docs/email-notifications.md
Completes send_action_completed_email HTML assembly (conditionally includes escaped error details), sends the multipart email, preserves get_email_service() singleton accessor, and adds docs describing SMTP env vars, provider guidance, notification types, and UI enable/verify steps.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Arvo-AI/aurora#435: Implements or extends the action-completion notification flow that calls EmailService.send_action_completed_email(...).

Suggested reviewers

  • damianloch
  • OlivierTrudeau

Poem

🐰 Midnight rabbit at the terminal, bright,
I stitch dark cards with accents of light,
Actions finish, reports take flight,
Aurora SRE sends them through the night,
Inbox dawns soft with tidy delight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately captures the primary change: redesigning email templates with a dark theme. However, it does not mention the significant addition of a new send_action_completed_email method, which represents a meaningful API expansion alongside the template redesign.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/email-templates-redesign

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/utils/notifications/email_service.py`:
- Around line 33-39: The code fails to validate SMTP_FROM_EMAIL so
self.from_email can be None; update EmailService initialization to treat
SMTP_FROM_EMAIL as required like the others by adding it to the validation loop
(or explicitly checking self.from_email) and raise a ValueError with a clear
message if missing (reference SMTP_FROM_EMAIL, self.from_email, and the
EmailService constructor/initializer where SMTP_HOST/SMTP_USER/SMTP_PASSWORD are
validated).
- Around line 159-239: Import the stdlib html module (import html), then escape
all user-controlled values before interpolating into the content string: create
safe_* variables (e.g. safe_alert_title = html.escape(alert_title),
safe_source_type = html.escape(source_type), safe_severity =
html.escape(severity), safe_service = html.escape(service), safe_started_str =
html.escape(started_str), safe_incident_url = html.escape(incident_url,
quote=True)) and replace the direct uses of alert_title, source_type, severity,
service, started_str, incident_url in the content variable with these safe_*
names; apply the same safe_* pattern for any other user-controlled fields in
this method and other email-building methods in the class to prevent HTML
injection.
- Line 452: The session URL construction in email_service.py should URL-encode
session_id before interpolation to avoid malformed URLs; import
urllib.parse.quote and replace the string interpolation that sets session_url
(which references self.frontend_url and session_id) with one that encodes
session_id (e.g., using quote(session_id, safe='')) so the generated URL is safe
when session_id contains special characters.
- Around line 464-475: The template directly interpolates error_msg into
error_section which risks HTML injection; before constructing error_section
escape error_msg using html.escape (import html if missing) and use the escaped
value when formatting the HTML string (look for error_msg and error_section in
this block). Ensure you only escape the content (not the surrounding HTML) so
the message renders safely.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4838ddc1-a67a-4794-ada2-5215935d371f

📥 Commits

Reviewing files that changed from the base of the PR and between a504821 and a604f9b.

📒 Files selected for processing (1)
  • server/utils/notifications/email_service.py

Comment thread server/utils/notifications/email_service.py
Comment thread server/utils/notifications/email_service.py
Comment thread server/utils/notifications/email_service.py Outdated
Comment thread server/utils/notifications/email_service.py
…de session_id

- Add SMTP_FROM_EMAIL to required env var validation
- HTML-escape all user-controlled values before template interpolation
- URL-encode session_id in action completion email URLs
- Escape error_msg in action failure error section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
server/utils/notifications/email_service.py (1)

470-470: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

server/utils/notifications/email_service.py: cast session_id to str before quote()

send_action_completed_email builds the action link with quote(session_id, ...) when session_id is truthy. urllib.parse.quote() raises TypeError for non-string values (e.g., int, UUID), which can break email generation—cast to str before encoding.

Proposed fix
-        session_url = f"{self.frontend_url}/actions?session={quote(session_id, safe='')}" if session_id else f"{self.frontend_url}/actions"
+        session_url = f"{self.frontend_url}/actions?session={quote(str(session_id), safe='')}" if session_id else f"{self.frontend_url}/actions"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/utils/notifications/email_service.py` at line 470, In
send_action_completed_email, the session_url construction calls
urllib.parse.quote(session_id, ...) which can TypeError if session_id isn't a
str; fix by casting session_id to str before quoting (e.g., use
quote(str(session_id), safe='')) so session_url always receives a string; update
the line that builds session_url in send_action_completed_email to wrap
session_id with str() while keeping the existing frontend_url and conditional
logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@server/utils/notifications/email_service.py`:
- Line 470: In send_action_completed_email, the session_url construction calls
urllib.parse.quote(session_id, ...) which can TypeError if session_id isn't a
str; fix by casting session_id to str before quoting (e.g., use
quote(str(session_id), safe='')) so session_url always receives a string; update
the line that builds session_url in send_action_completed_email to wrap
session_id with str() while keeping the existing frontend_url and conditional
logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: fd1c42b0-3fdc-4735-a7b6-ae657882c6ab

📥 Commits

Reviewing files that changed from the base of the PR and between a604f9b and 6edddcd.

📒 Files selected for processing (1)
  • server/utils/notifications/email_service.py

Resolve conflict in email_service.py: keep html_mod alias used
throughout the branch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread server/utils/notifications/email_service.py Fixed
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/utils/notifications/email_service.py`:
- Around line 561-657: Remove the duplicate send_action_completed_email method
block that overrides the correct implementation (the second definition that
calls _get_logo_url, _email_header_html, _status_banner_html,
_alert_title_card_html, _detail_field_html, _cta_button_html, and
_email_footer_html); delete this entire duplicate method so the original
send_action_completed_email (the one that uses existing helpers) remains and no
AttributeError occurs at runtime.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 73b8a589-3493-4afc-9ed9-532ff87352e2

📥 Commits

Reviewing files that changed from the base of the PR and between 6edddcd and 41f9425.

📒 Files selected for processing (1)
  • server/utils/notifications/email_service.py

Comment thread server/utils/notifications/email_service.py Outdated
- Remove duplicate send_action_completed_email method from merge
- Replace hardcoded aurora-ai.net with FRONTEND_URL env var throughout
- Fix action email link path (/chat?sessionId= not /actions?session=)
- Remove SendGrid-specific references from docstring
- Add docs/email-notifications.md with SMTP setup guide for self-hosters

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/utils/notifications/email_service.py (1)

419-423: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

verification_code is not HTML-escaped, unlike other user-controlled values.

For consistency with the escaping pattern applied in other email methods, verification_code should be escaped before HTML interpolation. While verification codes are typically system-generated alphanumeric strings, applying escaping provides defense-in-depth.

Proposed fix
+        safe_code = html_mod.escape(verification_code)
+
         content = f"""
                     <!-- Header -->
...
                             <div style="font-size: 36px; font-weight: 700; letter-spacing: 12px; color: `#ffffff`; font-family: 'SF Mono', 'Fira Code', 'Courier New', monospace;">
-                                    {verification_code}
+                                    {safe_code}
                                 </div>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/utils/notifications/email_service.py` around lines 419 - 423, The
verification_code is interpolated into the HTML template without HTML-escaping;
locate the email-building function (e.g., the method that renders the
verification email in EmailService — look for send_verification_email or the
template-building function that declares verification_code) and HTML-escape the
value before interpolation (use the same escape utility used elsewhere in this
file/module for user-controlled values) so the template inserts
escaped_verification_code instead of raw verification_code to maintain
consistent escaping and defense-in-depth.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/utils/notifications/email_service.py`:
- Around line 470-471: The URL-quoting call quote(session_id, safe='') in the
session_url construction is redundant because session_id is already typed as a
str along the call path (set in _send_action_completion_notification and passed
to send_action_completed_email); remove the quote(...) call and use session_id
directly (or if you prefer defensive coding, cast to str(session_id)) when
building session_url in send_action_completed_email so the code no longer risks
a TypeError while preserving the existing HTML escaping later.

---

Outside diff comments:
In `@server/utils/notifications/email_service.py`:
- Around line 419-423: The verification_code is interpolated into the HTML
template without HTML-escaping; locate the email-building function (e.g., the
method that renders the verification email in EmailService — look for
send_verification_email or the template-building function that declares
verification_code) and HTML-escape the value before interpolation (use the same
escape utility used elsewhere in this file/module for user-controlled values) so
the template inserts escaped_verification_code instead of raw verification_code
to maintain consistent escaping and defense-in-depth.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9e8d9922-f6dd-48bb-861b-9f0e06271da9

📥 Commits

Reviewing files that changed from the base of the PR and between 41f9425 and 5f07c45.

📒 Files selected for processing (2)
  • docs/email-notifications.md
  • server/utils/notifications/email_service.py

Comment thread server/utils/notifications/email_service.py
Pass ssl.create_default_context() to starttls() so certificate
verification is explicit rather than relying on Python version defaults.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comment thread server/utils/notifications/email_service.py Fixed
Comment thread server/utils/notifications/email_service.py Fixed
beng360 and others added 2 commits May 30, 2026 17:12
create_default_context() alone doesn't satisfy the rule — need explicit
PROTOCOL_TLS_CLIENT with minimum_version set to TLSv1_2.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SonarCloud flags smtplib.SMTP regardless of STARTTLS because the initial
connection is plaintext. Support both: SMTP_SSL on port 465 (default),
STARTTLS on port 587 when explicitly configured.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
1 Security Hotspot

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants