Skip to content

Email Base Notification to Support HTTP and SMTP with similar capability to other notifiers#3516

Draft
RandithaK wants to merge 2 commits into
thunder-id:mainfrom
RandithaK:improvement/email-notifier-smtp-http-support
Draft

Email Base Notification to Support HTTP and SMTP with similar capability to other notifiers#3516
RandithaK wants to merge 2 commits into
thunder-id:mainfrom
RandithaK:improvement/email-notifier-smtp-http-support

Conversation

@RandithaK

@RandithaK RandithaK commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Purpose

fixes #3276
Introduces a unified Notification Sender management system to replace the legacy SMTP-based email sender, with support for both SMTP and HTTP based email support.


⚠️ Breaking Changes

🔧 Summary of Breaking Changes

Describe what is changing
Deployment yaml based SMTP senders are no longer used for system level notifications, such as user onboarding and have to set the notifier manually through the flow builder.

💥 Impact

What will break? Who is affected?
All flows that used Email, such as User invite, Magic Link, and Password Reset.

🔄 Migration Guide

How should users update their code/configuration to adapt to the breaking changes? Include examples if helpful

Setup it as a email provider following the documentation.


Approach

  • Backend: Defined a new abstraction NotificationSenderServiceInterface to support various underlying notification channels without tightly coupling the executor logic.
  • Frontend: Added property fields in the email configuration modals to sender selection.

Related Issues

  • N/A

Related PRs

  • N/A

Checklist

  • Followed the contribution guidelines.
  • Manual test round performed and verified.
  • Documentation provided. (Add links if there are any)
    • Ran Vale and fixed all errors and warnings
  • Tests provided. (Add links if there are any)
    • Unit Tests
    • Integration Tests
  • Breaking changes. (Fill if applicable)
    • Breaking changes section filled.
    • breaking change label added.

Security checks

  • Followed secure coding standards in WSO2 Secure Coding Guidelines
  • Confirmed that this PR doesn't commit any keys, passwords, tokens, usernames, or other secrets.

Summary by CodeRabbit

Summary

  • New Features
    • Added email notification sender REST API endpoints for listing, creating, and managing senders (/notification-senders/email/...).
    • Introduced SMTP and HTTP email providers and added sender selection in the console.
    • Auto-assigns senderId for email executors and added editor validation to require senderId.
  • Bug Fixes
    • Improved delivery error handling and clarified misconfiguration messaging to reference email providers.
  • Documentation
    • Added the Email Providers guide and updated “getting started” and flow executor references to it.

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 4cfe4e0b-a1a8-4f55-9ed1-30310524ad30

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

Walkthrough

Adds email sender API endpoints, backend sender/service/client support, console sender selection, and docs/test updates for SMTP and HTTP email providers.

Changes

Email provider support

Layer / File(s) Summary
Public API and sender contracts
api/notification-sender.yaml, backend/internal/notification/common/*, backend/internal/notification/client/client.go, backend/internal/notification/NotificationSenderServiceInterface_mock_test.go
Email sender endpoints, sender type constants, payload models, client interfaces, and notification service mock methods add email sender support.
Sender handler and validation
backend/internal/notification/handler.go, backend/internal/notification/init.go, backend/internal/notification/utils.go, backend/internal/notification/handler_test.go, backend/internal/notification/utils_test.go
Message and email sender handlers are split by sender type, new email routes are registered, and email sender validation and handler tests are updated.
Notification clients and factory
backend/internal/notification/client/*, backend/internal/system/email/*, backend/internal/system/config/config.go, backend/cmd/server/servicemanager.go
Client selection branches by sender type, SMS clients switch to MessageData, new HTTP and SMTP email clients plus their tests are added, and legacy system email wiring/config is removed.
Runtime wiring and config removal
backend/cmd/server/servicemanager.go, backend/internal/flow/executor/register.go, backend/internal/system/config/config.go
Legacy email client wiring and email config fields are removed from startup and executor dependency wiring.
Message send service and OTP
backend/internal/notification/notification_sender_service.go, backend/internal/notification/otp_service.go, backend/internal/flow/executor/sms_executor.go, backend/internal/notification/*_test.go, backend/internal/flow/executor/sms_executor_test.go
SMS and OTP sending move to SendMessage with MessageData, and the related tests are updated.
Email executor send path
backend/internal/flow/executor/email_executor.go, backend/internal/flow/executor/email_executor_test.go, backend/internal/flow/executor/error_constants.go, backend/internal/system/i18n/core/defaults.go
The email flow executor resolves senderId, calls SendEmail with EmailData, and updates misconfiguration/error handling and tests.
Console sender selection
frontend/apps/console/src/features/flows/validation/validation-rules.ts, frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx, frontend/apps/console/src/features/login-flow/components/resource-property-panel/extended-properties/execution-properties/EmailProperties.tsx, frontend/apps/console/src/features/notification-senders/api/useNotificationSenders.ts, frontend/apps/console/src/features/notification-senders/constants/query-keys.ts, frontend/packages/i18n/src/locales/en-US.ts
The console fetches message/email sender lists, auto-fills email sender IDs, renders email sender selection, and adds email executor validation and strings.
Docs updates
docs/content/guides/**, docs/content/use-cases/**, docs/sidebars.ts
Docs and navigation now refer to Email Providers and include SMTP and HTTP email provider guidance.
Integration helpers and tests
tests/integration/**
Integration helpers and flow/auth/recovery/notification tests create and delete message or email notification senders using the new endpoints.

Sequence Diagram(s)

sequenceDiagram
  participant Console
  participant Notification API
  participant NotificationSenderService
  participant EmailExecutor
  participant SMTPEmailClient
  Console->>Notification API: create/list email sender
  Notification API->>NotificationSenderService: persist sender data
  EmailExecutor->>NotificationSenderService: SendEmail(senderID, EmailData)
  NotificationSenderService->>SMTPEmailClient: Send(email data)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~90+ minutes

Possibly related PRs

  • thunder-id/thunderid#1655: Shares the same email-client and email-config wiring area that this PR replaces in executor/runtime startup.
  • thunder-id/thunderid#2677: Also changes backend/internal/flow/executor/email_executor.go error handling and send-path behavior.
  • thunder-id/thunderid#3397: Touches the notification client/service pipeline used by the same sender lookup and send flow.

Suggested reviewers

  • ThaminduDilshan
  • darshanasbg
  • rajithacharith
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The added consent block in backend/cmd/server/deployment.yaml appears unrelated to email provider management and #3276. Remove or justify the deployment.yaml consent addition, or split it into a separate PR if it belongs to another feature.
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is clearly related to the main change set: moving email notifications to API-managed SMTP/HTTP providers.
Description check ✅ Passed The PR description includes Purpose, Breaking Changes, Approach, Related Issues, Checklist, and Security checks, matching the template well.
Linked Issues check ✅ Passed The changes add API-managed email sender CRUD, SMTP/HTTP provider support, and runtime flow resolution, matching #3276.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Bundle Report

Changes will decrease total bundle size by 63.7kB (-0.25%) ⬇️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
gate-esm 2.91MB -56.44kB (-1.9%) ⬇️
console-esm 22.05MB -7.26kB (-0.03%) ⬇️

Affected Assets, Files, and Routes:

view changes for bundle: gate-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/dist-*.js -9.01kB 375.68kB -2.34%
assets/en-*.js 299 bytes 190.05kB 0.16%
assets/index-*.js -2.37kB 100.19kB -2.31%
assets/AuthOptionFactory-*.js 207 bytes 64.56kB 0.32%
assets/SignInPage-*.js -24.52kB 21.38kB -53.42%
assets/SignUpPage-*.js -6.67kB 14.73kB -31.18%
assets/AcceptInvitePage-*.js 300 bytes 13.3kB 2.31%
assets/RecoveryPage-*.js -6.87kB 10.26kB -40.08%
assets/getAuthComponentHeadings-*.js -7.04kB 4.36kB -61.77%
assets/passkey-*.js -3 bytes 2.8kB -0.11%
assets/useForm-*.js (New) 2.15kB 2.15kB 100.0% 🚀
assets/Logo-*.js (Deleted) -2.92kB 0 bytes -100.0% 🗑️
view changes for bundle: console-esm

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/LoginFlowPage-*.js 1.89kB 2.4MB 0.08%
assets/useThunderID-*.js -3.43kB 260.68kB -1.3%
assets/index-*.js -2.36kB 199.02kB -1.17%
assets/en-*.js 299 bytes 190.05kB 0.16%
assets/resolveStaticResourcePath-*.js 7 bytes 151.93kB 0.0%
assets/dist-*.js 10 bytes 140 bytes 7.69% ⚠️
assets/dist-*.js 9 bytes 154 bytes 6.21% ⚠️
assets/dist-*.js -78 bytes 70 bytes -52.7%
assets/dist-*.js 75 bytes 145 bytes 107.14% ⚠️
assets/dist-*.js -5 bytes 73.31kB -0.01%
assets/dist-*.js -24 bytes 130 bytes -15.58%
assets/dist-*.js 136.42kB 136.56kB 97445.0% ⚠️
assets/dist-*.js 615 bytes 130.37kB 0.47%
assets/dist-*.js -136.41kB 148 bytes -99.89%
assets/ApplicationCreatePage-*.js 15 bytes 68.98kB 0.02%
assets/useQuery-*.js -4 bytes 14.79kB -0.03%
assets/VerifiablePresentationsListPage-*.js -1 bytes 12.52kB -0.01%
assets/VerifiableCredentialsListPage-*.js -1 bytes 10.16kB -0.01%
assets/VerifiableCredentialCreatePage-*.js -1.85kB 8.8kB -17.36%
assets/VerifiablePresentationCreatePage-*.js -2.44kB 8.39kB -22.5%

@Malith-19 Malith-19 added Type/Improvement breaking change The feature/ improvement will alter the existing behaviour labels Jun 24, 2026
@RandithaK RandithaK force-pushed the improvement/email-notifier-smtp-http-support branch from 08678a6 to cf899f6 Compare June 24, 2026 10:22
@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

@RandithaK

Copy link
Copy Markdown
Contributor Author

The PR is split into multiple smaller commits for my ease of development, and would be made to a single commit before merging.

@RandithaK RandithaK marked this pull request as ready for review June 25, 2026 08:48
Copilot AI review requested due to automatic review settings June 25, 2026 08:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@RandithaK RandithaK marked this pull request as draft June 25, 2026 08:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

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

⚠️ Outside diff range comments (2)
docs/content/guides/guides/flows/advanced-configurations.mdx (1)

290-290: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use “Email Provider” here, not SMTP.

Recovery email delivery is provider-based now, so this prerequisite should not narrow the setup to SMTP. Please reword it to require an Email Provider so HTTP-backed senders are covered.

🤖 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 `@docs/content/guides/guides/flows/advanced-configurations.mdx` at line 290,
The prerequisite text currently says “SMTP,” but this flow now uses
provider-based recovery delivery. Update the wording in the relevant guide
section to require an “Email Provider” instead, using the surrounding flow setup
copy in advanced-configurations.mdx so HTTP-backed senders are included.
docs/content/guides/getting-started/configuration.mdx (1)

658-674: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Replace the stale SMTP setup section, not just the link.

The surrounding copy still tells readers to configure SMTP in deployment.yaml, which conflicts with the new runtime-managed Email Providers flow and the updated destination. Please rewrite this whole section to describe API-managed email providers and remove the restart/deployment.yaml guidance.

🤖 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 `@docs/content/guides/getting-started/configuration.mdx` around lines 658 -
674, The “Email Configuration” section is stale and still instructs readers to
configure SMTP in deployment.yaml, which conflicts with the new runtime-managed
Email Providers flow. Rewrite the entire section anchored by “Email
Configuration” to describe API-managed email providers, update the surrounding
copy and example so it no longer references deployment.yaml or restart-based
setup, and point readers to the updated Email Providers destination with the
correct runtime configuration guidance.
🧹 Nitpick comments (6)
tests/integration/flow/recovery/basic_recovery_test.go (1)

114-132: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant sender tracking — senderID stored twice.

The created email sender ID is saved to both ts.emailSenderID (Line 128) and ts.config.CreatedSenderIDs (Line 129), but TearDownSuite only cleans up via ts.emailSenderID. The append to CreatedSenderIDs is dead state here. Worth dropping to avoid confusion, especially since other suites iterate CreatedSenderIDs with DeleteMessageNotificationSender — if that pattern is ever shared, an email sender ID in that slice would be deleted against the wrong (/message) endpoint.

🤖 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 `@tests/integration/flow/recovery/basic_recovery_test.go` around lines 114 -
132, The email sender ID is being tracked twice in the recovery test setup, but
only ts.emailSenderID is used for cleanup. Remove the redundant append to
ts.config.CreatedSenderIDs in the test setup around
CreateEmailNotificationSender so the sender is tracked in one place only and the
teardown path stays unambiguous.
backend/internal/notification/client/http_email_client_test.go (1)

70-81: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent provider for an email FORM fixture.

getValidCustomSenderFORM sets Provider: common.MessageProviderTypeCustom while Type is NotificationSenderTypeEmail. Since newHTTPEmailClient is invoked directly here the provider value is effectively ignored, but for clarity and to mirror the real email-routing path it should use common.MessageProviderTypeHTTP like the JSON fixture.

♻️ Suggested tweak
-		Provider: common.MessageProviderTypeCustom,
+		Provider: common.MessageProviderTypeHTTP,
🤖 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 `@backend/internal/notification/client/http_email_client_test.go` around lines
70 - 81, The email FORM fixture in getValidCustomSenderFORM uses an inconsistent
provider for an HTTP-based email client test. Update the NotificationSenderDTO
returned by getValidCustomSenderFORM to use common.MessageProviderTypeHTTP so it
matches the JSON fixture and the intended HTTP email path, while keeping the
NotificationSenderTypeEmail and existing properties unchanged.
api/notification-sender.yaml (1)

1139-1142: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor schema inconsistency: properties is required for email senders but not for message senders.

EmailNotificationSender lists properties under required, whereas MessageNotificationSender (Line 1167-1169) only requires name and provider. If this divergence is intentional (email senders cannot be created without provider config), it's fine; otherwise consider aligning the two for a consistent client contract.

🤖 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 `@api/notification-sender.yaml` around lines 1139 - 1142, The notification
sender schemas are inconsistent because EmailNotificationSender requires
properties while MessageNotificationSender does not. Review the sender
definitions in notification-sender.yaml and either align
MessageNotificationSender with EmailNotificationSender by adding properties to
its required list, or confirm the difference is intentional and keep both
contracts explicitly consistent in the schema definitions.
backend/internal/notification/client/custom_client.go (2)

85-140: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Duplication with HTTPEmailClient.Send. The JSON/FORM request construction, header application, and non-2xx response handling here largely mirror http_email_client.go. Extracting a shared helper (e.g., a doWebhookRequest on httpWebhookConfig) would reduce drift between the two webhook senders.

🤖 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 `@backend/internal/notification/client/custom_client.go` around lines 85 - 140,
The request-building and response-handling logic in CustomClient.sendSMS is
duplicated from HTTPEmailClient.Send, so factor the shared JSON/FORM request
creation, header application, and non-2xx error handling into a common helper
such as a doWebhookRequest method on httpWebhookConfig or a shared utility. Keep
sendSMS focused on SMS-specific logging and body preparation, and have both
senders call the shared helper to avoid drift between custom_client.go and the
email client implementation.

85-118: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Custom httpHeaders are applied after the Content-Type header, so they can silently override it.

req.Header.Set(ContentTypeHeaderName, ...) is set in the JSON/FORM branch, then the loop at Lines 116-118 re-applies all configured headers. If an admin includes a Content-Type entry in http_headers, it overrides the format-derived value and may break encoding. Consider applying custom headers first, or skipping Content-Type in the loop.

🤖 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 `@backend/internal/notification/client/custom_client.go` around lines 85 - 118,
The CustomClient.sendSMS header setup currently lets c.config.httpHeaders
override the Content-Type chosen by the JSON/FORM branches, which can break
request encoding. Update sendSMS so the format-derived Content-Type set via
req.Header.Set is preserved, either by applying custom headers before setting
Content-Type or by skipping Content-Type in the loop over c.config.httpHeaders.
Use the sendSMS function and the c.config.httpHeaders iteration as the key
places to change.
backend/internal/flow/executor/register.go (1)

142-142: 📐 Maintainability & Code Quality | 🔵 Trivial

The EmailClient dependency field at line 142 is no longer used.

The email executor has been migrated to use NotifSenderSvc. Since this field is no longer accessed anywhere in backend/internal/flow/executor, it should be removed to reduce technical debt.

🤖 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 `@backend/internal/flow/executor/register.go` at line 142, The EmailClient
dependency field is unused in the executor dependency struct and should be
removed. Update the dependency definition in the register-related executor type
that currently includes EmailClient, and make sure any construction or
initialization code in backend/internal/flow/executor no longer passes or
expects it since the email executor now uses NotifSenderSvc instead.
🤖 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 `@backend/internal/flow/executor/error_constants.go`:
- Around line 561-573: The ErrEmailProviderNotConfigured service error in
error_constants.go references i18n keys that are missing from the en-US
translation bundle. Add both flows.executor.errors.email_provider_not_configured
and flows.executor.errors.email_provider_not_configured_desc to
backend/cmd/server/bootstrap/i18n/en-US.json, matching the wording used in the
ErrEmailProviderNotConfigured I18nMessage so the executor can resolve localized
text instead of falling back to defaults.

In `@backend/internal/notification/client/smtp_email_client.go`:
- Around line 127-129: The CRLF check in Send currently covers only
emailData.Subject, but buildMessage also writes From, To, and Cc directly into
SMTP headers. Update Send and/or buildMessage in smtp_email_client.go to
validate every address-bearing field (configured from-address, recipients, and
cc) before composing the message, rejecting any value with CRLF or parsing
addresses safely with net/mail.ParseAddress. Use the existing Send and
buildMessage flow to locate the validation points and ensure all header inputs
are sanitized consistently.
- Around line 102-106: The SMTP client validation currently allows
enableAuthentication without requiring TLS, which can later fail when PlainAuth
is used. Update the constructor validation path in SmtpEmailClient creation and
the matching config check in the TLS/auth setup block so that when
enableAuthentication is true and TLS is not explicitly enabled, the method
returns a configuration error immediately. Use the existing config flags
(enableAuthentication and enableTLS) in both validation locations to keep the
behavior consistent.

In `@backend/internal/notification/client/utils.go`:
- Around line 39-70: `parseHTTPWebhookConfig` currently returns a config even
when `common.CustomPropKeyURL` is missing or empty, so add an explicit non-empty
URL validation before returning the `httpWebhookConfig`. Update the
`parseHTTPWebhookConfig` function to fail fast with an error if `config.url` was
never set during the sender.Properties loop, keeping the function self-contained
and aligned with the existing URL invariant enforced elsewhere.

In `@backend/internal/notification/utils.go`:
- Around line 159-167: Update validateSMTPProperties to inspect the
enable_authentication property and, when it is true, add username and password
as required fields in the requiredProps map before calling
validateSenderProperties. Keep the existing host, port, and from_address checks
intact, and align the validation rules with newSMTPEmailClient so configurations
with authentication enabled are rejected during validation instead of failing
later at send time.

In `@docs/content/use-cases/b2c/try-it-out/account-recovery.mdx`:
- Around line 21-23: Remove the restart step from the provider setup
instructions in the account recovery walkthrough, since Email providers are now
configured at runtime. Update the surrounding text in the recovery flow so it
only tells users to configure the Email Provider via the Email Providers guide,
and if any later step still requires a restart, mention that separately in the
relevant section rather than here.

In
`@frontend/apps/console/src/features/login-flow/components/resource-property-panel/extended-properties/execution-properties/EmailProperties.tsx`:
- Around line 59-80: The EmailProperties UI is using SMS-specific translation
keys for its sender label, placeholder, and empty-state text. Update the strings
referenced in EmailProperties to use email-appropriate i18n keys (preferably
under an email sender namespace, or a neutral shared namespace) instead of the
current smsOtp.sender.* keys. Make sure the Select, MenuItem placeholder, and
Alert copy all point to the new email-specific translations so the email panel
shows the correct wording.

---

Outside diff comments:
In `@docs/content/guides/getting-started/configuration.mdx`:
- Around line 658-674: The “Email Configuration” section is stale and still
instructs readers to configure SMTP in deployment.yaml, which conflicts with the
new runtime-managed Email Providers flow. Rewrite the entire section anchored by
“Email Configuration” to describe API-managed email providers, update the
surrounding copy and example so it no longer references deployment.yaml or
restart-based setup, and point readers to the updated Email Providers
destination with the correct runtime configuration guidance.

In `@docs/content/guides/guides/flows/advanced-configurations.mdx`:
- Line 290: The prerequisite text currently says “SMTP,” but this flow now uses
provider-based recovery delivery. Update the wording in the relevant guide
section to require an “Email Provider” instead, using the surrounding flow setup
copy in advanced-configurations.mdx so HTTP-backed senders are included.

---

Nitpick comments:
In `@api/notification-sender.yaml`:
- Around line 1139-1142: The notification sender schemas are inconsistent
because EmailNotificationSender requires properties while
MessageNotificationSender does not. Review the sender definitions in
notification-sender.yaml and either align MessageNotificationSender with
EmailNotificationSender by adding properties to its required list, or confirm
the difference is intentional and keep both contracts explicitly consistent in
the schema definitions.

In `@backend/internal/flow/executor/register.go`:
- Line 142: The EmailClient dependency field is unused in the executor
dependency struct and should be removed. Update the dependency definition in the
register-related executor type that currently includes EmailClient, and make
sure any construction or initialization code in backend/internal/flow/executor
no longer passes or expects it since the email executor now uses NotifSenderSvc
instead.

In `@backend/internal/notification/client/custom_client.go`:
- Around line 85-140: The request-building and response-handling logic in
CustomClient.sendSMS is duplicated from HTTPEmailClient.Send, so factor the
shared JSON/FORM request creation, header application, and non-2xx error
handling into a common helper such as a doWebhookRequest method on
httpWebhookConfig or a shared utility. Keep sendSMS focused on SMS-specific
logging and body preparation, and have both senders call the shared helper to
avoid drift between custom_client.go and the email client implementation.
- Around line 85-118: The CustomClient.sendSMS header setup currently lets
c.config.httpHeaders override the Content-Type chosen by the JSON/FORM branches,
which can break request encoding. Update sendSMS so the format-derived
Content-Type set via req.Header.Set is preserved, either by applying custom
headers before setting Content-Type or by skipping Content-Type in the loop over
c.config.httpHeaders. Use the sendSMS function and the c.config.httpHeaders
iteration as the key places to change.

In `@backend/internal/notification/client/http_email_client_test.go`:
- Around line 70-81: The email FORM fixture in getValidCustomSenderFORM uses an
inconsistent provider for an HTTP-based email client test. Update the
NotificationSenderDTO returned by getValidCustomSenderFORM to use
common.MessageProviderTypeHTTP so it matches the JSON fixture and the intended
HTTP email path, while keeping the NotificationSenderTypeEmail and existing
properties unchanged.

In `@tests/integration/flow/recovery/basic_recovery_test.go`:
- Around line 114-132: The email sender ID is being tracked twice in the
recovery test setup, but only ts.emailSenderID is used for cleanup. Remove the
redundant append to ts.config.CreatedSenderIDs in the test setup around
CreateEmailNotificationSender so the sender is tracked in one place only and the
teardown path stays unambiguous.
🪄 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: CHILL

Plan: Pro Plus

Run ID: a10b777d-3a7a-46a3-868f-19b613d794e2

📥 Commits

Reviewing files that changed from the base of the PR and between 2661170 and 95d1be7.

⛔ Files ignored due to path filters (4)
  • backend/tests/mocks/notification/clientmock/EmailClientInterface_mock.go is excluded by !**/*_mock.go
  • backend/tests/mocks/notification/clientmock/MessageClientInterface_mock.go is excluded by !**/*_mock.go
  • backend/tests/mocks/notification/clientmock/NotificationClientInterface_mock.go is excluded by !**/*_mock.go
  • backend/tests/mocks/notification/notificationmock/NotificationSenderServiceInterface_mock.go is excluded by !**/*_mock.go
📒 Files selected for processing (62)
  • api/notification-sender.yaml
  • backend/internal/flow/executor/email_executor.go
  • backend/internal/flow/executor/email_executor_test.go
  • backend/internal/flow/executor/error_constants.go
  • backend/internal/flow/executor/register.go
  • backend/internal/flow/executor/sms_executor.go
  • backend/internal/flow/executor/sms_executor_test.go
  • backend/internal/notification/NotificationSenderServiceInterface_mock_test.go
  • backend/internal/notification/client/client.go
  • backend/internal/notification/client/custom_client.go
  • backend/internal/notification/client/custom_client_test.go
  • backend/internal/notification/client/factory.go
  • backend/internal/notification/client/factory_test.go
  • backend/internal/notification/client/http_email_client.go
  • backend/internal/notification/client/http_email_client_test.go
  • backend/internal/notification/client/smtp_email_client.go
  • backend/internal/notification/client/smtp_email_client_test.go
  • backend/internal/notification/client/twilio_client.go
  • backend/internal/notification/client/twilio_client_test.go
  • backend/internal/notification/client/utils.go
  • backend/internal/notification/client/utils_test.go
  • backend/internal/notification/client/vonage_client.go
  • backend/internal/notification/client/vonage_client_test.go
  • backend/internal/notification/common/constants.go
  • backend/internal/notification/common/model.go
  • backend/internal/notification/handler.go
  • backend/internal/notification/handler_test.go
  • backend/internal/notification/init.go
  • backend/internal/notification/notification_sender_service.go
  • backend/internal/notification/notification_sender_service_test.go
  • backend/internal/notification/otp_service.go
  • backend/internal/notification/otp_service_test.go
  • backend/internal/notification/utils.go
  • backend/internal/notification/utils_test.go
  • backend/internal/system/i18n/core/defaults.go
  • docs/content/guides/getting-started/configuration.mdx
  • docs/content/guides/guides/flows/advanced-configurations.mdx
  • docs/content/guides/guides/notifications/email-providers.mdx
  • docs/content/guides/guides/smtp-server/smtp-server-configuration.mdx
  • docs/content/guides/key-concepts/authentication/passwordless/magiclink.mdx
  • docs/content/use-cases/b2c/configure-it-yourself.mdx
  • docs/content/use-cases/b2c/try-it-out/account-recovery.mdx
  • docs/content/use-cases/b2c/try-it-out/onboard-internal-users.mdx
  • docs/sidebars.ts
  • frontend/apps/console/src/features/flows/validation/validation-rules.ts
  • frontend/apps/console/src/features/login-flow/components/LoginFlowBuilder.tsx
  • frontend/apps/console/src/features/login-flow/components/resource-property-panel/extended-properties/execution-properties/EmailProperties.tsx
  • frontend/apps/console/src/features/notification-senders/api/useNotificationSenders.ts
  • frontend/apps/console/src/features/notification-senders/constants/query-keys.ts
  • tests/integration/authn/sms_otp_auth_test.go
  • tests/integration/flow/authentication/assurance_test.go
  • tests/integration/flow/authentication/prompt_actions_test.go
  • tests/integration/flow/authentication/sms_auth_test.go
  • tests/integration/flow/common/utils.go
  • tests/integration/flow/recovery/basic_recovery_test.go
  • tests/integration/flow/recovery/sms_otp_recovery_test.go
  • tests/integration/flow/registration/http_request_executor_runtime_data_test.go
  • tests/integration/flow/registration/ou_registration_test.go
  • tests/integration/flow/registration/sms_registration_test.go
  • tests/integration/notification/message/notificationsenderapi_test.go
  • tests/integration/notification/message/otpapi_test.go
  • tests/integration/testutils/api_utils.go
💤 Files with no reviewable changes (1)
  • docs/content/guides/guides/smtp-server/smtp-server-configuration.mdx

Comment thread backend/internal/flow/executor/error_constants.go
Comment thread backend/internal/notification/client/smtp_email_client.go
Comment thread backend/internal/notification/client/smtp_email_client.go
Comment thread backend/internal/notification/client/utils.go
Comment thread backend/internal/notification/utils.go
Comment thread docs/content/use-cases/b2c/try-it-out/account-recovery.mdx Outdated
@RandithaK RandithaK marked this pull request as ready for review June 25, 2026 09:50
@RandithaK RandithaK marked this pull request as draft June 26, 2026 09:26
@RandithaK RandithaK force-pushed the improvement/email-notifier-smtp-http-support branch from 09a9e62 to 8ca70a8 Compare June 30, 2026 07:17
@RandithaK RandithaK marked this pull request as ready for review June 30, 2026 07:17
Comment thread backend/internal/flow/executor/email_executor.go Outdated
Comment thread backend/internal/flow/executor/email_executor.go Outdated
Comment thread backend/internal/flow/executor/email_executor.go Outdated
Comment thread backend/internal/notification/client/utils_test.go
@RandithaK RandithaK marked this pull request as draft June 30, 2026 15:19
@RandithaK RandithaK marked this pull request as ready for review June 30, 2026 15:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 `@backend/internal/notification/client/utils_test.go`:
- Line 25: The tests in utils_test use assert for prerequisite checks, but later
call err.Error() on the same value, so a failed check can still panic and mask
the real issue. Update the gate checks in these tests to use require.* instead
of assert.* for conditions like error presence, while keeping assert.* for the
remaining value comparisons. Focus on the test cases in utils_test that validate
errors before dereferencing them.
🪄 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: CHILL

Plan: Pro Plus

Run ID: 340eee76-0ffa-4f5f-b518-e05e727af8c1

📥 Commits

Reviewing files that changed from the base of the PR and between 8ca70a8 and 1a64878.

📒 Files selected for processing (1)
  • backend/internal/notification/client/utils_test.go

Comment thread backend/internal/notification/client/utils_test.go
Comment thread tests/integration/notification/message/notificationsenderapi_test.go Outdated
enable_start_tls: true
enable_authentication: true
```
1. Invitation emails are delivered through an Email provider. **Configure an Email Provider** in <ProductName />. See [Email Providers](../../../guides/guides/notifications/email-providers.mdx).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Let's discus on an approach to keep the config here, without being difficult to maintain

@RandithaK

RandithaK commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Follow-Ups - To Be Considered After this PR is merged

)

const (
smtpLoggerComponentName = "SMTPEmailClient"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's get rid of these logger constants. Check all other places as well

Comment thread backend/internal/notification/client/http_email_client.go
bodyBytes, _ := io.ReadAll(resp.Body)
logger.Error(ctx, "Failed to send Email via HTTP client", log.Int("statusCode", resp.StatusCode),
log.String("response", string(bodyBytes)))
return fmt.Errorf("HTTP Email send failed, status: %d, response: %s", resp.StatusCode, string(bodyBytes))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Client should send a go error.
Logging is done in backend/internal/notification/notification_sender_service.go

}

// SMTPEmailClient implements the EmailClientInterface using SMTP.
type SMTPEmailClient struct {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shall we try to make this private?

}

// newSMTPEmailClient creates a new instance of SMTPEmailClient.
func newSMTPEmailClient(ctx context.Context, sender common.NotificationSenderDTO) (EmailClientInterface, error) {

@RandithaK RandithaK Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Make a private helper function to pass the sender configs, and return


// Send dispatches an email notification via SMTP.
func (c *SMTPEmailClient) Send(ctx context.Context, emailData common.EmailData) error {
logger := log.GetLogger().With(log.String(log.LoggerKeyComponentName, smtpLoggerComponentName))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's initialize logger inside struct and use here rather than initializing in each method

Comment on lines +95 to +109
if config.from == "" {
return nil, errors.New("from_address is missing")
}
if config.host == "" {
return nil, errors.New("host is missing")
}
if config.port <= 0 {
return nil, errors.New("port is invalid")
}
if config.enableAuthentication {
if !config.useTLS {
return nil, errors.New("TLS must be enabled when authentication is enabled")
}
if config.username == "" || config.password == "" {
return nil, errors.New("credentials are required when authentication is enabled")

@RandithaK RandithaK Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Let's do this inline, and not seperately.

Within the switchCase


for _, addressList := range [][]string{emailData.To, emailData.CC, emailData.BCC} {
for _, address := range addressList {
if strings.ContainsAny(address, "\r\n") {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Deal with
/r/n
With Go Language Package

}
}

if strings.ContainsAny(emailData.Subject, "\r\n") {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Better to deal with
\r\n
With a trim, not a error

return errors.New("subject contains invalid characters")
}

if strings.ContainsAny(c.config.from, "\r\n") {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Better to take all these

strings.ContainsAny(c.config.from, "\r\n")

To a external, function.
Check on previous implementation, systemEmailValivator.go

)

// IsValidEmail returns true for syntactically valid email addresses.
func IsValidEmail(emailAddr string) bool {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Better to keep this to perform the email validations inside notification email sender. Move to an appropriate place

builder.WriteString(fmt.Sprintf("Cc: %s\r\n", strings.Join(emailData.CC, ", ")))
}
builder.WriteString(fmt.Sprintf("Subject: %s\r\n", mime.QEncoding.Encode("utf-8", emailData.Subject)))
builder.WriteString("MIME-Version: 1.0\r\n")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shall we define constants for these?

Comment on lines +199 to +206
client, err := smtp.NewClient(conn, c.config.host)
if err != nil {
_ = conn.Close()
return fmt.Errorf("smtp connection failed: %w", err)
}
defer func() {
_ = client.Close()
}()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If the error scenario is there,
If error, 204, is always executed, not need to have 201.

return fmt.Errorf("email send failed: %w", err)
}

if err := client.Quit(); err != nil {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Check why use client.quit...
Case is if client.close, did not work, we force close...

Check where the defer function is actually executed, after registering.

return fmt.Errorf("smtp connection failed: %w", err)
}
defer func() {
_ = client.Close()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If there is an error, better to log it in here.

Comment on lines +209 to +211
ok, _ := client.Extension("STARTTLS")
if !ok {
return errors.New("smtp connection failed: STARTTLS not supported by server")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Currently useTLS, needs STARTTLS,

Check whether there are clients who needs TLS from the begining.

Comment on lines +222 to +226
if c.config.enableAuthentication && c.config.username != "" && c.config.password != "" {
if !c.config.useTLS {
return errors.New("smtp connection failed: TLS must be enabled when authentication is enabled")
}
if err := client.Auth(smtp.PlainAuth("", c.config.username, c.config.password, c.config.host)); err != nil {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Check, might be correct.

Does TLS need auth and password

Clients, might have username password, but no TLS

@RandithaK

RandithaK commented Jul 1, 2026

Copy link
Copy Markdown
Contributor Author

Task

  • Add WayFinder, Declarative resources

@RandithaK RandithaK marked this pull request as draft July 1, 2026 10:07
@RandithaK RandithaK force-pushed the improvement/email-notifier-smtp-http-support branch from 55b20fc to d7359fc Compare July 1, 2026 10:11
@RandithaK RandithaK marked this pull request as ready for review July 1, 2026 10:12
builder.WriteString("MIME-Version: 1.0\r\n")

if emailData.IsHTML {
builder.WriteString("Content-Type: text/html; charset=\"utf-8\"\r\n")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shall we define constants for these?

@RandithaK RandithaK marked this pull request as draft July 2, 2026 02:17
@RandithaK RandithaK force-pushed the improvement/email-notifier-smtp-http-support branch from d7359fc to ba64e86 Compare July 2, 2026 02:36
Authored-by: RandithaK <me@randitha.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change The feature/ improvement will alter the existing behaviour Type/Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support email provider configurations via API along with HTTP providers support

5 participants