Repository: wireapp/wire-ios
Pull request #2621: feat: Implement "email already in use" error alert - WPB-15936
Author: login: KaterinaWire
Created: 2025-03-03T08:40:39Z | Merged: 2025-03-05T11:49:39Z

<!--do not remove the jira markers to link tickets automatically -->
<!--jira-description-action-hidden-marker-start-->

<!--jira-description-action-hidden-marker-end-->

### Issue

If the backend detects that the email is already registered to a cloud account, the backend acts as if the domain was not registered (returning` { domain_registration: none, due_to_existing_account: true }`), allowing the client to continue the log in via password even if the domain was registered.

**Note:**  To ensure that the existence of the account in the Wire cloud is not publicly visible, we should display an alert after the user enters the credentials. Since we move the user to the "No History" screen after a successful response, the alert can be displayed there. There are no strict requirements from the design. @samwyndham @johnxnguyen Let me know if you have any objections.

### Needs releases with:
https://github.com/wireapp/wire-ios-build-assets/pull/148

From the user's perspective, we should display a warning:

![Screenshot 2025-03-03 at 09 39 38](https://github.com/user-attachments/assets/8fe6a6c7-188c-4707-8140-8acf04c615ed)


### Testing

### Checklist

- [x] Title contains a reference JIRA issue number like `[WPB-XXX]`.
- [x] Description is filled and free of optional paragraphs.
- [ ] Adds/updates automated tests.

---

### UI accessibility checklist

_If your PR includes UI changes, please utilize this checklist:_
- [ ] Make sure you use the API for UI elements that support large fonts.
- [ ] All colors are taken from WireDesign.ColorTheme or constructed using WireDesign.BaseColorPalette.
- [ ] New UI elements have Accessibility strings for VoiceOver.



Diff:
diff --git a/WireAuthentication/Sources/WireAuthentication/Components/DetermineAuthMethodComponent.swift b/WireAuthentication/Sources/WireAuthentication/Components/DetermineAuthMethodComponent.swift
index b41a4861949..3232016d455 100644
--- a/WireAuthentication/Sources/WireAuthentication/Components/DetermineAuthMethodComponent.swift
+++ b/WireAuthentication/Sources/WireAuthentication/Components/DetermineAuthMethodComponent.swift
@@ -95,10 +95,16 @@ class DetermineAuthMethodComponent: Component<DetermineAuthMethodComponentDepend
 
 extension DetermineAuthMethodComponent: DetermineAuthMethodView.Factory {
 
-    func loginViaEmailView(email: String, canCreateAccount: Bool) -> LoginViaEmailView {
+    @MainActor
+    func loginViaEmailView(
+        email: String,
+        canCreateAccount: Bool,
+        didDetectDomainConflict: Bool
+    ) -> LoginViaEmailView {
         loginViaEmailComponent.view(
             email: email,
-            canCreateAccount: canCreateAccount
+            canCreateAccount: canCreateAccount,
+            didDetectDomainConflict: didDetectDomainConflict
         )
     }
 
diff --git a/WireAuthentication/Sources/WireAuthentication/Components/LoginViaEmailComponent.swift b/WireAuthentication/Sources/WireAuthentication/Components/LoginViaEmailComponent.swift
index e835311c385..4a2ddabce9f 100644
--- a/WireAuthentication/Sources/WireAuthentication/Components/LoginViaEmailComponent.swift
+++ b/WireAuthentication/Sources/WireAuthentication/Components/LoginViaEmailComponent.swift
@@ -43,9 +43,17 @@ class LoginViaEmailComponent: Component<LoginViaEmailComponentDependency> {
     // MARK: - View
 
     @MainActor
-    func view(email: String, canCreateAccount: Bool) -> LoginViaEmailView {
+    func view(
+        email: String,
+        canCreateAccount: Bool,
+        didDetectDomainConflict: Bool
+    ) -> LoginViaEmailView {
         LoginViaEmailView(
-            viewModel: viewModel(email: email, canCreateAccount: canCreateAccount),
+            viewModel: viewModel(
+                email: email,
+                canCreateAccount: canCreateAccount,
+                didDetectDomainConflict: didDetectDomainConflict
+            ),
             factory: self
         )
     }
@@ -53,7 +61,8 @@ class LoginViaEmailComponent: Component<LoginViaEmailComponentDependency> {
     @MainActor
     private func viewModel(
         email: String,
-        canCreateAccount: Bool
+        canCreateAccount: Bool,
+        didDetectDomainConflict: Bool
     ) -> LoginViaEmailViewModel {
         LoginViaEmailViewModel(
             router: dependency.router,
@@ -62,6 +71,7 @@ class LoginViaEmailComponent: Component<LoginViaEmailComponentDependency> {
             accountsURL: dependency.accountsURL,
             passwordValidator: dependency.passwordValidator,
             canCreateAccount: canCreateAccount,
+            didDetectDomainConflict: didDetectDomainConflict,
             onCreateAccount: { [weak dependency] in
                 dependency?.bridge.registerAccount()
             }
@@ -78,8 +88,16 @@ class LoginViaEmailComponent: Component<LoginViaEmailComponentDependency> {
 
 extension LoginViaEmailComponent: LoginViaEmailView.Factory {
 
-    func verificationCodeView(email: String, password: String) -> VerificationCodeView {
-        verificationCodeComponent.view(email: email, password: password)
+    func verificationCodeView(
+        email: String,
+        password: String,
+        didDetectDomainConflict: Bool
+    ) -> VerificationCodeView {
+        verificationCodeComponent.view(
+            email: email,
+            password: password,
+            didDetectDomainConflict: didDetectDomainConflict
+        )
     }
 
 }
diff --git a/WireAuthentication/Sources/WireAuthentication/Components/NoHistoryComponent.swift b/WireAuthentication/Sources/WireAuthentication/Components/NoHistoryComponent.swift
index f30848ed15a..dee4a7e4be1 100644
--- a/WireAuthentication/Sources/WireAuthentication/Components/NoHistoryComponent.swift
+++ b/WireAuthentication/Sources/WireAuthentication/Components/NoHistoryComponent.swift
@@ -16,40 +16,59 @@
 // along with this program. If not, see http://www.gnu.org/licenses/.
 //
 
-import Foundation
+import NeedleFoundation
+import SwiftUI
 import WireAuthenticationAPI
 internal import WireAuthenticationUI
+internal import WireAuthenticationLogic
+import WireReusableUIComponents
 
-class NoHistoryComponent {
+protocol NoHistoryComponentDependency: Dependency {
 
-    let onFlowCompletion: (AuthenticationResult) -> Void
+    var howToChangeEmailURL: URL { get }
+    var howToDeleteAccountURL: URL { get }
 
-    init(onFlowCompletion: @escaping (AuthenticationResult) -> Void) {
-        self.onFlowCompletion = onFlowCompletion
-    }
+}
+
+class NoHistoryComponent: Component<NoHistoryComponentDependency> {
 
     @MainActor
     private func viewModel(
         userID: UUID,
         cookies: [HTTPCookie],
         accessToken: AccessToken?,
+        didDetectDomainConflict: Bool,
+        howToChangeEmailURL: URL,
+        howToDeleteAccountURL: URL,
         onFlowCompletion: @escaping (AuthenticationResult) -> Void
     ) -> NoHistoryViewModel {
         NoHistoryViewModel(
             userID: userID,
             cookies: cookies,
             accessToken: accessToken,
+            didDetectDomainConflict: didDetectDomainConflict,
+            howToChangeEmailURL: howToChangeEmailURL,
+            howToDeleteAccountURL: howToDeleteAccountURL,
             onFlowCompletion: onFlowCompletion
         )
     }
 
     @MainActor
-    func view(userID: UUID, cookies: [HTTPCookie], accessToken: AccessToken?) -> NoHistoryView {
+    func view(
+        userID: UUID,
+        cookies: [HTTPCookie],
+        accessToken: AccessToken?,
+        didDetectDomainConflict: Bool,
+        onFlowCompletion: @escaping (AuthenticationResult) -> Void
+    ) -> NoHistoryView {
         NoHistoryView(
             viewModel: viewModel(
                 userID: userID,
                 cookies: cookies,
                 accessToken: accessToken,
+                didDetectDomainConflict: didDetectDomainConflict,
+                howToChangeEmailURL: dependency.howToChangeEmailURL,
+                howToDeleteAccountURL: dependency.howToDeleteAccountURL,
                 onFlowCompletion: onFlowCompletion
             )
         )
diff --git a/WireAuthentication/Sources/WireAuthentication/Components/RootComponent.swift b/WireAuthentication/Sources/WireAuthentication/Components/RootComponent.swift
index 55498a259e5..8f6ffaccdad 100644
--- a/WireAuthentication/Sources/WireAuthentication/Components/RootComponent.swift
+++ b/WireAuthentication/Sources/WireAuthentication/Components/RootComponent.swift
@@ -29,6 +29,8 @@ class RootComponent: BootstrapComponent {
     public let defaultAPIVersion: APIVersion
     public let minTLSVersion: TLSVersion
     public let accountsURL: URL
+    public let howToChangeEmailURL: URL
+    public let howToDeleteAccountURL: URL
     public let passwordValidator: any PasswordValidator
     public let ssoCallbackURLScheme: String
     public let userDefaults: UserDefaults
@@ -40,6 +42,8 @@ class RootComponent: BootstrapComponent {
         defaultAPIVersion: APIVersion,
         minTLSVersion: TLSVersion,
         accountsURL: URL,
+        howToChangeEmailURL: URL,
+        howToDeleteAccountURL: URL,
         passwordValidator: any PasswordValidator,
         ssoCallbackURLScheme: String,
         userDefaults: UserDefaults,
@@ -50,6 +54,8 @@ class RootComponent: BootstrapComponent {
         self.defaultAPIVersion = defaultAPIVersion
         self.minTLSVersion = minTLSVersion
         self.accountsURL = accountsURL
+        self.howToChangeEmailURL = howToChangeEmailURL
+        self.howToDeleteAccountURL = howToDeleteAccountURL
         self.passwordValidator = passwordValidator
         self.ssoCallbackURLScheme = ssoCallbackURLScheme
         self.userDefaults = userDefaults
@@ -96,7 +102,7 @@ class RootComponent: BootstrapComponent {
     }
 
     @MainActor var noHistoryComponent: NoHistoryComponent {
-        NoHistoryComponent(onFlowCompletion: bridge.onFlowCompletion)
+        NoHistoryComponent(parent: self)
     }
 
 }
@@ -111,9 +117,16 @@ extension RootComponent: RootView.Factory {
     func noHistoryView(
         userID: UUID,
         cookies: [HTTPCookie],
-        accessToken: WireAuthenticationAPI.AccessToken?
+        accessToken: WireAuthenticationAPI.AccessToken?,
+        didDetectDomainConflict: Bool
     ) -> NoHistoryView {
-        noHistoryComponent.view(userID: userID, cookies: cookies, accessToken: accessToken)
+        noHistoryComponent.view(
+            userID: userID,
+            cookies: cookies,
+            accessToken: accessToken,
+            didDetectDomainConflict: didDetectDomainConflict,
+            onFlowCompletion: bridge.onFlowCompletion
+        )
     }
 
 }
diff --git a/WireAuthentication/Sources/WireAuthentication/Components/VerificationCodeComponent.swift b/WireAuthentication/Sources/WireAuthentication/Components/VerificationCodeComponent.swift
index a6dbfcdef15..4e3e3a93251 100644
--- a/WireAuthentication/Sources/WireAuthentication/Components/VerificationCodeComponent.swift
+++ b/WireAuthentication/Sources/WireAuthentication/Components/VerificationCodeComponent.swift
@@ -39,23 +39,29 @@ class VerificationCodeComponent: Component<VerificationCodeComponentDependency>
     }
 
     @MainActor
-    func view(email: String, password: String) -> VerificationCodeView {
+    func view(email: String, password: String, didDetectDomainConflict: Bool) -> VerificationCodeView {
         VerificationCodeView(
             viewModel: viewModel(
                 email: email,
-                password: password
+                password: password,
+                didDetectDomainConflict: didDetectDomainConflict
             )
         )
     }
 
     @MainActor
-    private func viewModel(email: String, password: String) -> VerificationCodeViewModel {
+    private func viewModel(
+        email: String,
+        password: String,
+        didDetectDomainConflict: Bool
+    ) -> VerificationCodeViewModel {
         VerificationCodeViewModel(
             email: email,
             password: password,
             loginViaEmailUseCase: dependency.loginViaEmailUseCase,
             requestLoginVerificationCodeUseCase: requestLoginVerificationCodeUseCase,
-            router: dependency.router
+            router: dependency.router,
+            didDetectDomainConflict: didDetectDomainConflict
         )
     }
 
diff --git a/WireAuthentication/Sources/WireAuthentication/Needle.generated.swift b/WireAuthentication/Sources/WireAuthentication/Needle.generated.swift
index aabc0fe0634..0612db1e4d8 100644
--- a/WireAuthentication/Sources/WireAuthentication/Needle.generated.swift
+++ b/WireAuthentication/Sources/WireAuthentication/Needle.generated.swift
@@ -80,6 +80,22 @@ private class DetermineAuthMethodComponentDependency527e70b5dbcfcb8f2023Provider
 private func factoryd47fa74281e135cd9f10b3a8f24c1d289f2c0f2e(_ component: NeedleFoundation.Scope) -> AnyObject {
     return DetermineAuthMethodComponentDependency527e70b5dbcfcb8f2023Provider(rootComponent: parent1(component) as! RootComponent)
 }
+private class NoHistoryComponentDependency0df6cc26e7db3dd9d951Provider: NoHistoryComponentDependency {
+    var howToChangeEmailURL: URL {
+        return rootComponent.howToChangeEmailURL
+    }
+    var howToDeleteAccountURL: URL {
+        return rootComponent.howToDeleteAccountURL
+    }
+    private let rootComponent: RootComponent
+    init(rootComponent: RootComponent) {
+        self.rootComponent = rootComponent
+    }
+}
+/// ^->RootComponent->NoHistoryComponent
+private func factory3bfed346df783964230ab3a8f24c1d289f2c0f2e(_ component: NeedleFoundation.Scope) -> AnyObject {
+    return NoHistoryComponentDependency0df6cc26e7db3dd9d951Provider(rootComponent: parent1(component) as! RootComponent)
+}
 private class LoginViaEmailComponentDependency6f812ea9ca4f0322dd27Provider: LoginViaEmailComponentDependency {
     var router: any Router {
         return rootComponent.router
@@ -134,6 +150,8 @@ extension RootComponent: NeedleFoundation.Registration {
         localTable["defaultAPIVersion-APIVersion"] = { [unowned self] in self.defaultAPIVersion as Any }
         localTable["minTLSVersion-TLSVersion"] = { [unowned self] in self.minTLSVersion as Any }
         localTable["accountsURL-URL"] = { [unowned self] in self.accountsURL as Any }
+        localTable["howToChangeEmailURL-URL"] = { [unowned self] in self.howToChangeEmailURL as Any }
+        localTable["howToDeleteAccountURL-URL"] = { [unowned self] in self.howToDeleteAccountURL as Any }
         localTable["passwordValidator-any PasswordValidator"] = { [unowned self] in self.passwordValidator as Any }
         localTable["ssoCallbackURLScheme-String"] = { [unowned self] in self.ssoCallbackURLScheme as Any }
         localTable["userDefaults-UserDefaults"] = { [unowned self] in self.userDefaults as Any }
@@ -142,6 +160,12 @@ extension RootComponent: NeedleFoundation.Registration {
         localTable["router-any Router"] = { [unowned self] in self.router as Any }
     }
 }
+extension NoHistoryComponent: NeedleFoundation.Registration {
+    public func registerItems() {
+        keyPathToName[\NoHistoryComponentDependency.howToChangeEmailURL] = "howToChangeEmailURL-URL"
+        keyPathToName[\NoHistoryComponentDependency.howToDeleteAccountURL] = "howToDeleteAccountURL-URL"
+    }
+}
 extension LoginViaEmailComponent: NeedleFoundation.Registration {
     public func registerItems() {
         keyPathToName[\LoginViaEmailComponentDependency.router] = "router-any Router"
@@ -171,6 +195,7 @@ private func registerProviderFactory(_ componentPath: String, _ factory: @escapi
     registerProviderFactory("^->RootComponent->DetermineAuthMethodComponent->LoginViaEmailComponent->VerificationCodeComponent", factoryd3638676a47fce1fe623cded1e126cd6f1df3cee)
     registerProviderFactory("^->RootComponent->DetermineAuthMethodComponent", factoryd47fa74281e135cd9f10b3a8f24c1d289f2c0f2e)
     registerProviderFactory("^->RootComponent", factoryEmptyDependencyProvider)
+    registerProviderFactory("^->RootComponent->NoHistoryComponent", factory3bfed346df783964230ab3a8f24c1d289f2c0f2e)
     registerProviderFactory("^->RootComponent->DetermineAuthMethodComponent->LoginViaEmailComponent", factory9bda312c16141c932061c770221f242f9204cf85)
 }
 #endif
diff --git a/WireAuthentication/Sources/WireAuthentication/WireAuthenticationAssembly.swift b/WireAuthentication/Sources/WireAuthentication/WireAuthenticationAssembly.swift
index ff5e541a732..041950d9712 100644
--- a/WireAuthentication/Sources/WireAuthentication/WireAuthenticationAssembly.swift
+++ b/WireAuthentication/Sources/WireAuthentication/WireAuthenticationAssembly.swift
@@ -37,6 +37,8 @@ public struct WireAuthenticationAssembly {
         minTLSVersion: TLSVersion,
         defaultAPIVersion: APIVersion,
         accountsURL: URL,
+        howToChangeEmailURL: URL,
+        howToDeleteAccountURL: URL,
         passwordValidator: any PasswordValidator,
         ssoCallbackURLScheme: String,
         userDefaults: UserDefaults,
@@ -48,6 +50,8 @@ public struct WireAuthenticationAssembly {
             defaultAPIVersion: defaultAPIVersion,
             minTLSVersion: minTLSVersion,
             accountsURL: accountsURL,
+            howToChangeEmailURL: howToChangeEmailURL,
+            howToDeleteAccountURL: howToDeleteAccountURL,
             passwordValidator: passwordValidator,
             ssoCallbackURLScheme: ssoCallbackURLScheme,
             userDefaults: userDefaults,
diff --git a/WireAuthentication/Sources/WireAuthenticationAPI/Use cases/DetermineAuthMethodUseCaseProtocol.swift b/WireAuthentication/Sources/WireAuthenticationAPI/Use cases/DetermineAuthMethodUseCaseProtocol.swift
index 0635da27efa..d7b1b912e96 100644
--- a/WireAuthentication/Sources/WireAuthenticationAPI/Use cases/DetermineAuthMethodUseCaseProtocol.swift	
+++ b/WireAuthentication/Sources/WireAuthenticationAPI/Use cases/DetermineAuthMethodUseCaseProtocol.swift	
@@ -29,7 +29,7 @@ public enum AuthenticationMethod: Sendable, Hashable {
 
     /// Cloud login only
 
-    case loginViaEmail(email: String)
+    case loginViaEmail(email: String, didDetectDomainConflict: Bool)
 
     ///  Cloud login or registration.
 
@@ -49,11 +49,6 @@ public enum DetermineAuthMethodUseCaseFailure: Error, Equatable {
 
     case invalidEmailOrSSOCode
 
-    /// The email domain has been claimed by an on-prem backend but there's already an existing cloud account registered
-    /// - note: To proceed, alert the use then continue to login using the `recovery` method.
-
-    case onPremNotPossible(recovery: AuthenticationMethod)
-
     /// Indicates that the domain registration response was invalid.
 
     case invalidResponse
diff --git a/WireAuthentication/Sources/WireAuthenticationLogic/DetermineAuthMethodUseCase.swift b/WireAuthentication/Sources/WireAuthenticationLogic/DetermineAuthMethodUseCase.swift
index e0165a61373..aa0c514ad4b 100644
--- a/WireAuthentication/Sources/WireAuthenticationLogic/DetermineAuthMethodUseCase.swift
+++ b/WireAuthentication/Sources/WireAuthenticationLogic/DetermineAuthMethodUseCase.swift
@@ -83,13 +83,15 @@ package struct DetermineAuthMethodUseCase: DetermineAuthMethodUseCaseProtocol {
 
         switch configuration.domainRedirect {
         case .none where configuration.isCloudAccountAlreadyRegistered == true:
-            throw DetermineAuthMethodUseCaseFailure.onPremNotPossible(recovery: .loginViaEmail(email: email))
+            // The email domain has been claimed by an on-prem backend,
+            // but there's already an existing cloud account registered.
+            return .loginViaEmail(email: email, didDetectDomainConflict: true)
 
         case .none, .locked, .preAuthorized:
             return .loginOrRegisterViaEmail(email: email)
 
         case .noRegistration:
-            return .loginViaEmail(email: email)
+            return .loginViaEmail(email: email, didDetectDomainConflict: false)
 
         case .sso:
             guard let ssoCode = configuration.ssoCode else {
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/MockDependencies.swift b/WireAuthentication/Sources/WireAuthenticationUI/MockDependencies.swift
index 67378390e0c..ba59ad677d8 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/MockDependencies.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/MockDependencies.swift
@@ -86,7 +86,7 @@ extension MockDependencies: DetermineAuthMethodUseCaseProtocol {
     ) async throws(DetermineAuthMethodUseCaseFailure) -> AuthenticationMethod {
         try! await Task.sleep(for: .seconds(3))
 
-        return .loginViaEmail(email: emailOrSSOCode)
+        return .loginViaEmail(email: emailOrSSOCode, didDetectDomainConflict: false)
     }
 }
 
@@ -133,10 +133,23 @@ extension MockDependencies: DetermineAuthMethodBuilder {
 extension MockDependencies: NoHistoryViewBuilder {
 
     private var noHistoryViewModel: NoHistoryViewModel {
-        NoHistoryViewModel(userID: UUID(), cookies: [], accessToken: nil, onFlowCompletion: { _ in })
+        NoHistoryViewModel(
+            userID: UUID(),
+            cookies: [],
+            accessToken: nil,
+            didDetectDomainConflict: false,
+            howToChangeEmailURL: URL(string: "https://wire.com")!,
+            howToDeleteAccountURL: URL(string: "https://wire.com")!,
+            onFlowCompletion: { _ in }
+        )
     }
 
-    func noHistoryView(userID: UUID, cookies: [HTTPCookie], accessToken: AccessToken?) -> NoHistoryView {
+    func noHistoryView(
+        userID: UUID,
+        cookies: [HTTPCookie],
+        accessToken: AccessToken?,
+        didDetectDomainConflict: Bool
+    ) -> NoHistoryView {
         NoHistoryView(viewModel: noHistoryViewModel)
     }
 
@@ -162,11 +175,16 @@ extension MockDependencies: LoginViaEmailBuilder {
             accountsURL: URL(string: "https://example.com")!,
             passwordValidator: MockPasswordValidator(validationCallback: { _ in true }),
             canCreateAccount: canCreateAccount,
+            didDetectDomainConflict: false,
             onCreateAccount: {}
         )
     }
 
-    func loginViaEmailView(email: String, canCreateAccount: Bool) -> LoginViaEmailView {
+    func loginViaEmailView(
+        email: String,
+        canCreateAccount: Bool,
+        didDetectDomainConflict: Bool
+    ) -> LoginViaEmailView {
         LoginViaEmailView(
             viewModel: loginViewModel(email: email, canCreateAccount: canCreateAccount),
             factory: self
@@ -188,7 +206,8 @@ extension MockDependencies: VerificationCodeBuilder {
             loginViaEmailUseCase: self,
             requestLoginVerificationCodeUseCase: self,
             router: rootViewModel,
-            numberOfDigits: code.count
+            numberOfDigits: code.count,
+            didDetectDomainConflict: false
         )
         viewModel.code = code
 
@@ -197,7 +216,8 @@ extension MockDependencies: VerificationCodeBuilder {
 
     func verificationCodeView(
         email: String,
-        password: String
+        password: String,
+        didDetectDomainConflict: Bool
     ) -> VerificationCodeView {
         VerificationCodeView(
             viewModel: VerificationCodeViewModel(
@@ -205,7 +225,8 @@ extension MockDependencies: VerificationCodeBuilder {
                 password: password,
                 loginViaEmailUseCase: self,
                 requestLoginVerificationCodeUseCase: self,
-                router: rootViewModel
+                router: rootViewModel,
+                didDetectDomainConflict: false
             )
         )
     }
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Resources/Localization/en.lproj/Localizable.strings b/WireAuthentication/Sources/WireAuthenticationUI/Resources/Localization/en.lproj/Localizable.strings
index 9d67a4dbaa7..6af166f408c 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Resources/Localization/en.lproj/Localizable.strings
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Resources/Localization/en.lproj/Localizable.strings
@@ -67,7 +67,6 @@
 
 "authentication.error.title.no_internet" = "No internet";
 "authentication.error.title.general" = "Error";
-"authentication.error.title.on_prem_not_possible" = "On prem not possible";
 "authentication.error.title.invalid_sso_link" = "Error";
 "authentication.error.title.sso_login_failed" = "Something went wrong";
 "authentication.error.title.invalid_credentials" = "Invalid Information";
@@ -77,7 +76,6 @@
 
 "authentication.error.message.no_internet" = "You are not connected to the internet.";
 "authentication.error.message.general" = "Something went wrong";
-"authentication.error.message.email_is_already_registered" = "Email is already registered on Wire Cloud.";
 "authentication.error.message.invalid_sso_link" = "Invalid company login url.";
 "authentication.error.message.sso_login_failed" = "Please contact your team administrator for details.";
 "authentication.error.message.invalid_credentials" = "These account credentials are incorrect. Please verify your details and try again.";
@@ -86,3 +84,8 @@
 "authentication.error.message.account_suspended" = "This account is no longer authorized to log in.";
 
 "authentication.error.confirm" = "OK";
+
+"authentication.error.title.email_already_in_use" = "Email already in use";
+"authentication.error.message.email_already_in_use" = "This email's domain belongs to a Wire Enterprise Instance, but the email address is associated with a Wire Cloud account. To proceed with the Enterprise instance login, please update your email address to another domain, or delete your account. If the account is part of a team, please reach out to the Team Administrator.";
+"authentication.error.how_to_change_email" = "How to change email address";
+"authentication.error.how_to_delete_account" = "How to delete a private account";
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/DetermineAuthMethod/DetermineAuthMethodView.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/DetermineAuthMethod/DetermineAuthMethodView.swift
index 9efb4c9e0bb..783b227ddc8 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/DetermineAuthMethod/DetermineAuthMethodView.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/DetermineAuthMethod/DetermineAuthMethodView.swift
@@ -30,6 +30,7 @@ package struct DetermineAuthMethodView: View {
 
     package typealias Factory = LoginViaEmailBuilder & LoginViaSSOBuilder
 
+    @Environment(\.dismiss) var dismiss
     @StateObject var viewModel: DetermineAuthMethodViewModel
 
     let factory: any Factory
@@ -96,9 +97,9 @@ package struct DetermineAuthMethodView: View {
             item: $viewModel.alert,
             title: titleForAlert,
             message: messageForAlert,
-            actions: { alert in
+            actions: { _ in
                 Button {
-                    viewModel.didDismissAlert(alert: alert)
+                    dismiss()
                 } label: {
                     Text(L10n.Authentication.Error.confirm)
                 }
@@ -106,10 +107,18 @@ package struct DetermineAuthMethodView: View {
         )
         .navigationDestination(for: Destination.self) {
             switch $0 {
-            case let .login(email):
-                factory.loginViaEmailView(email: email, canCreateAccount: false)
+            case let .login(email, didDetectDomainConflict):
+                factory.loginViaEmailView(
+                    email: email,
+                    canCreateAccount: false,
+                    didDetectDomainConflict: didDetectDomainConflict
+                )
             case let .loginOrRegister(email):
-                factory.loginViaEmailView(email: email, canCreateAccount: true)
+                factory.loginViaEmailView(
+                    email: email,
+                    canCreateAccount: true,
+                    didDetectDomainConflict: false
+                )
             }
         }
         .sheet(item: $viewModel.modalDestination, content: {
@@ -125,7 +134,7 @@ package struct DetermineAuthMethodView: View {
 
     package enum Destination: Hashable {
 
-        case login(email: String)
+        case login(email: String, didDetectDomainConflict: Bool)
         case loginOrRegister(email: String)
 
     }
@@ -140,8 +149,6 @@ package struct DetermineAuthMethodView: View {
             Text(L10n.Authentication.Error.Title.general)
         case .unknownError:
             Text(L10n.Authentication.Error.Title.general)
-        case .onPremLoginNotPossible:
-            Text(L10n.Authentication.Error.Title.onPremNotPossible)
         case .invalidSSOLink:
             Text(L10n.Authentication.Error.Title.invalidSsoLink)
         }
@@ -155,8 +162,6 @@ package struct DetermineAuthMethodView: View {
             Text(L10n.Authentication.Error.Message.general)
         case .unknownError:
             Text(L10n.Authentication.Error.Message.general)
-        case .onPremLoginNotPossible:
-            Text(L10n.Authentication.Error.Message.emailIsAlreadyRegistered)
         case .invalidSSOLink:
             Text(L10n.Authentication.Error.Message.invalidSsoLink)
         }
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/DetermineAuthMethod/DetermineAuthMethodViewModel.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/DetermineAuthMethod/DetermineAuthMethodViewModel.swift
index 41fa41b971f..d16ed528c7d 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/DetermineAuthMethod/DetermineAuthMethodViewModel.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/DetermineAuthMethod/DetermineAuthMethodViewModel.swift
@@ -30,7 +30,6 @@ package final class DetermineAuthMethodViewModel: ObservableObject {
         case noInternet
         case invalidResponse
         case unknownError
-        case onPremLoginNotPossible(recovery: AuthenticationMethod)
         case invalidSSOLink
 
     }
@@ -85,8 +84,6 @@ package final class DetermineAuthMethodViewModel: ObservableObject {
                 // No need to do anything here. In general this shouldn't happen. It is probably worth restructuring
                 // things a little to make this error impossible to happen.
                 break
-            case let .onPremNotPossible(recovery):
-                alert = .onPremLoginNotPossible(recovery: recovery)
             case .invalidResponse:
                 alert = .invalidResponse
             case let .urlError(urlError):
@@ -104,15 +101,6 @@ package final class DetermineAuthMethodViewModel: ObservableObject {
         isLoading = false
     }
 
-    func didDismissAlert(alert: Alert) {
-        switch alert {
-        case let .onPremLoginNotPossible(method):
-            handleAuthenticationMethod(method)
-        default:
-            break
-        }
-    }
-
     func dismissmodalView() {
         ssoLinkGenerator.flushToken()
         modalDestination = nil
@@ -122,8 +110,11 @@ package final class DetermineAuthMethodViewModel: ObservableObject {
 
     private func handleAuthenticationMethod(_ method: AuthenticationMethod) {
         switch method {
-        case let .loginViaEmail(email):
-            router.navigate(to: DetermineAuthMethodView.Destination.login(email: email))
+        case let .loginViaEmail(email, didDetectDomainConflict):
+            router.navigate(to: DetermineAuthMethodView.Destination.login(
+                email: email,
+                didDetectDomainConflict: didDetectDomainConflict
+            ))
 
         case let .loginOrRegisterViaEmail(email):
             router.navigate(to: DetermineAuthMethodView.Destination.loginOrRegister(email: email))
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaEmail/LoginViaEmailView.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaEmail/LoginViaEmailView.swift
index 2985abd8c98..b20add73e80 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaEmail/LoginViaEmailView.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaEmail/LoginViaEmailView.swift
@@ -25,7 +25,8 @@ package protocol LoginViaEmailBuilder {
     @MainActor
     func loginViaEmailView(
         email: String,
-        canCreateAccount: Bool
+        canCreateAccount: Bool,
+        didDetectDomainConflict: Bool
     ) -> LoginViaEmailView
 
 }
@@ -78,7 +79,11 @@ package struct LoginViaEmailView: View {
         .navigationDestination(for: Destination.self) { destination in
             switch destination {
             case let .verifyLogin(email, password):
-                factory.verificationCodeView(email: email, password: password)
+                factory.verificationCodeView(
+                    email: email,
+                    password: password,
+                    didDetectDomainConflict: viewModel.didDetectDomainConflict
+                )
             }
         }
         .presentationDetents([.medium, .large])
@@ -182,6 +187,10 @@ package struct LoginViaEmailView: View {
 #Preview() {
     BackgroundView()
         .sheet(isPresented: .constant(true)) {
-            MockDependencies().loginViaEmailView(email: "foo@bar.com", canCreateAccount: false)
+            MockDependencies().loginViaEmailView(
+                email: "foo@bar.com",
+                canCreateAccount: false,
+                didDetectDomainConflict: false
+            )
         }
 }
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaEmail/LoginViaEmailViewModel.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaEmail/LoginViaEmailViewModel.swift
index 4cbd0ad46d5..9e564bd2c79 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaEmail/LoginViaEmailViewModel.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaEmail/LoginViaEmailViewModel.swift
@@ -41,6 +41,7 @@ package final class LoginViaEmailViewModel: ObservableObject {
 
     let email: String
     let canCreateAccount: Bool
+    let didDetectDomainConflict: Bool
 
     // MARK: - Life cycle
 
@@ -51,6 +52,7 @@ package final class LoginViaEmailViewModel: ObservableObject {
         accountsURL: URL,
         passwordValidator: any PasswordValidator,
         canCreateAccount: Bool,
+        didDetectDomainConflict: Bool,
         onCreateAccount: @escaping () -> Void
     ) {
         self.router = router
@@ -59,6 +61,7 @@ package final class LoginViaEmailViewModel: ObservableObject {
         self.forgotPasswordURL = accountsURL.appendingPathComponent("forgot")
         self.passwordValidator = passwordValidator
         self.canCreateAccount = canCreateAccount
+        self.didDetectDomainConflict = didDetectDomainConflict
         self.onCreateAccount = onCreateAccount
     }
 
@@ -87,7 +90,8 @@ package final class LoginViaEmailViewModel: ObservableObject {
                 RootView.ModalDestination.noHistory(
                     userID: token.userID,
                     cookies: cookies,
-                    accessToken: token
+                    accessToken: token,
+                    didDetectDomainConflict: didDetectDomainConflict
                 )
             )
             WireLogger.authentication.info("login via email succeeded")
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaSSO/SSOSuccessHandler.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaSSO/SSOSuccessHandler.swift
index bc65c62110a..d8c147d9b71 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaSSO/SSOSuccessHandler.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/LoginViaSSO/SSOSuccessHandler.swift
@@ -28,7 +28,14 @@ package struct SSOSuccessHandler {
 
     @MainActor
     package func handleSuccess(userID: UUID, cookies: [HTTPCookie]) {
-        router.presentSheet(RootView.ModalDestination.noHistory(userID: userID, cookies: cookies, accessToken: nil))
+        router.presentSheet(
+            RootView.ModalDestination.noHistory(
+                userID: userID,
+                cookies: cookies,
+                accessToken: nil,
+                didDetectDomainConflict: false
+            )
+        )
     }
 
 }
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryView.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryView.swift
index c63355f1d64..9f528857dc6 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryView.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryView.swift
@@ -22,7 +22,12 @@ import WireAuthenticationAPI
 package protocol NoHistoryViewBuilder {
 
     @MainActor
-    func noHistoryView(userID: UUID, cookies: [HTTPCookie], accessToken: AccessToken?) -> NoHistoryView
+    func noHistoryView(
+        userID: UUID,
+        cookies: [HTTPCookie],
+        accessToken: AccessToken?,
+        didDetectDomainConflict: Bool
+    ) -> NoHistoryView
 
 }
 
@@ -52,12 +57,43 @@ package struct NoHistoryView: View {
                 .wireButtonStyle(.primary)
                 .bold()
         }
+        .alert(
+            item: $viewModel.alert,
+            title: titleForAlert,
+            message: messageForAlert,
+            actions: { _ in
+                Button(L10n.Authentication.Error.howToChangeEmail, action: {
+                    viewModel.howToChangeEmail()
+                })
+                Button(L10n.Authentication.Error.howToDeleteAccount, action: {
+                    viewModel.howToDeleteAccount()
+                })
+                Button(L10n.Authentication.Error.confirm, action: {})
+            }
+        )
+        .onAppear {
+            viewModel.onAppear()
+        }
         .padding()
         .presentationDetents([.medium])
         .interactiveDismissDisabled()
         .presentationDragIndicator(.hidden)
     }
 
+    private func titleForAlert(_ alert: NoHistoryViewModel.Alert) -> Text {
+        switch alert {
+        case .cloudAccountAlreadyRegistered:
+            Text(L10n.Authentication.Error.Title.emailAlreadyInUse)
+        }
+    }
+
+    private func messageForAlert(_ alert: NoHistoryViewModel.Alert) -> Text {
+        switch alert {
+        case .cloudAccountAlreadyRegistered:
+            Text(L10n.Authentication.Error.Message.emailAlreadyInUse)
+        }
+    }
+
 }
 
 #Preview {
@@ -65,6 +101,9 @@ package struct NoHistoryView: View {
         userID: UUID(),
         cookies: [],
         accessToken: nil,
+        didDetectDomainConflict: false,
+        howToChangeEmailURL: URL(string: "https://wire.com")!,
+        howToDeleteAccountURL: URL(string: "https://wire.com")!,
         onFlowCompletion: { _ in }
     )
     NoHistoryView(viewModel: viewModel)
@@ -77,6 +116,9 @@ package struct NoHistoryView: View {
                 userID: UUID(),
                 cookies: [],
                 accessToken: nil,
+                didDetectDomainConflict: false,
+                howToChangeEmailURL: URL(string: "https://wire.com")!,
+                howToDeleteAccountURL: URL(string: "https://wire.com")!,
                 onFlowCompletion: { _ in }
             )
             NoHistoryView(viewModel: viewModel)
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryViewModel.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryViewModel.swift
index 01d485e118b..2c252a96e19 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryViewModel.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryViewModel.swift
@@ -24,24 +24,57 @@ import WireAuthenticationAPI
 @MainActor
 package final class NoHistoryViewModel: ObservableObject {
 
+    package enum Alert: Hashable, Identifiable, Sendable {
+        package var id: Self { self }
+
+        case cloudAccountAlreadyRegistered
+    }
+
+    @Published var alert: Alert?
+
     private let userID: UUID
     private let cookies: [HTTPCookie]
+    private let howToChangeEmailURL: URL
+    private let howToDeleteAccountURL: URL
     private let accessToken: AccessToken?
     private let onFlowCompletion: (AuthenticationResult) -> Void
 
+    let didDetectDomainConflict: Bool
+
     package init(
         userID: UUID,
         cookies: [HTTPCookie],
         accessToken: AccessToken?,
+        didDetectDomainConflict: Bool,
+        howToChangeEmailURL: URL,
+        howToDeleteAccountURL: URL,
         onFlowCompletion: @escaping (AuthenticationResult) -> Void
     ) {
         self.userID = userID
         self.cookies = cookies
         self.accessToken = accessToken
+        self.didDetectDomainConflict = didDetectDomainConflict
+        self.howToChangeEmailURL = howToChangeEmailURL
+        self.howToDeleteAccountURL = howToDeleteAccountURL
         self.onFlowCompletion = onFlowCompletion
     }
 
     func confirm() {
         onFlowCompletion(AuthenticationResult(userID: userID, cookies: cookies, accessToken: accessToken))
     }
+
+    func onAppear() {
+        if didDetectDomainConflict {
+            alert = .cloudAccountAlreadyRegistered
+        }
+    }
+
+    func howToChangeEmail() {
+        UIApplication.shared.open(howToChangeEmailURL)
+    }
+
+    func howToDeleteAccount() {
+        UIApplication.shared.open(howToDeleteAccountURL)
+    }
+
 }
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/VerificationCode/VerificationCodeView.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/VerificationCode/VerificationCodeView.swift
index c04c6cc111c..ca955c67f7a 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/VerificationCode/VerificationCodeView.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/VerificationCode/VerificationCodeView.swift
@@ -24,7 +24,8 @@ package protocol VerificationCodeBuilder {
     @MainActor
     func verificationCodeView(
         email: String,
-        password: String
+        password: String,
+        didDetectDomainConflict: Bool
     ) -> VerificationCodeView
 
 }
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/VerificationCode/VerificationCodeViewModel.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/VerificationCode/VerificationCodeViewModel.swift
index 2c14412150a..6c9dbc508ae 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/VerificationCode/VerificationCodeViewModel.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/Login/VerificationCode/VerificationCodeViewModel.swift
@@ -26,6 +26,7 @@ import WireLogging
 public final class VerificationCodeViewModel: ObservableObject {
 
     private static let numberOfDigits = 6
+    private let didDetectDomainConflict: Bool
 
     @Published var code: [String]
     @Published private(set) var isLoading = false
@@ -46,7 +47,8 @@ public final class VerificationCodeViewModel: ObservableObject {
         loginViaEmailUseCase: any LoginViaEmailUseCaseProtocol,
         requestLoginVerificationCodeUseCase: any RequestLoginVerificationCodeUseCaseProtocol,
         router: any Router,
-        numberOfDigits: Int = VerificationCodeViewModel.numberOfDigits
+        numberOfDigits: Int = VerificationCodeViewModel.numberOfDigits,
+        didDetectDomainConflict: Bool
     ) {
         precondition(numberOfDigits > 0)
 
@@ -57,6 +59,7 @@ public final class VerificationCodeViewModel: ObservableObject {
         self.router = router
         self.code = Array(repeating: "", count: numberOfDigits)
         self.numberOfDigits = numberOfDigits
+        self.didDetectDomainConflict = didDetectDomainConflict
     }
 
     var isConfirmButtonDisabled: Bool {
@@ -100,7 +103,8 @@ public final class VerificationCodeViewModel: ObservableObject {
                 RootView.ModalDestination.noHistory(
                     userID: token.userID,
                     cookies: cookies,
-                    accessToken: token
+                    accessToken: token,
+                    didDetectDomainConflict: didDetectDomainConflict
                 )
             )
             WireLogger.authentication.info("2FA login via email succeeded")
diff --git a/WireAuthentication/Sources/WireAuthenticationUI/Views/Root/RootView.swift b/WireAuthentication/Sources/WireAuthenticationUI/Views/Root/RootView.swift
index 71eb26e0a52..e7e81c3e616 100644
--- a/WireAuthentication/Sources/WireAuthenticationUI/Views/Root/RootView.swift
+++ b/WireAuthentication/Sources/WireAuthenticationUI/Views/Root/RootView.swift
@@ -50,8 +50,13 @@ package struct RootView: View {
                                 }
                             )
                     }
-                case let .noHistory(userID, cookies, accessToken):
-                    factory.noHistoryView(userID: userID, cookies: cookies, accessToken: accessToken)
+                case let .noHistory(userID, cookies, accessToken, didDetectDomainConflict):
+                    factory.noHistoryView(
+                        userID: userID,
+                        cookies: cookies,
+                        accessToken: accessToken,
+                        didDetectDomainConflict: didDetectDomainConflict
+                    )
                 }
 
             }
@@ -75,7 +80,12 @@ package struct RootView: View {
         public var id: Self { self }
 
         case authFlow
-        case noHistory(userID: UUID, cookies: [HTTPCookie], accessToken: AccessToken?)
+        case noHistory(
+            userID: UUID,
+            cookies: [HTTPCookie],
+            accessToken: AccessToken?,
+            didDetectDomainConflict: Bool
+        )
     }
 
 }
diff --git a/WireAuthentication/Tests/WireAuthenticationLogicTests/DetermineAuthMethodUseCaseTests.swift b/WireAuthentication/Tests/WireAuthenticationLogicTests/DetermineAuthMethodUseCaseTests.swift
index 989f79d9a22..a91d29c01ae 100644
--- a/WireAuthentication/Tests/WireAuthenticationLogicTests/DetermineAuthMethodUseCaseTests.swift
+++ b/WireAuthentication/Tests/WireAuthenticationLogicTests/DetermineAuthMethodUseCaseTests.swift
@@ -97,9 +97,19 @@ final class DetermineAuthMethodUseCaseTests: XCTestCase {
 
         let testCases: [(config: DomainRegistrationConfiguration, expected: AuthenticationMethod)] = [
             (config: .make(domainRedirect: .none), expected: .loginOrRegisterViaEmail(email: email)),
+            (
+                config: .make(domainRedirect: .none, isCloudAccountAlreadyRegistered: true),
+                expected: .loginViaEmail(email: email, didDetectDomainConflict: true)
+            ),
             (config: .make(domainRedirect: .locked), expected: .loginOrRegisterViaEmail(email: email)),
             (config: .make(domainRedirect: .preAuthorized), expected: .loginOrRegisterViaEmail(email: email)),
-            (config: .make(domainRedirect: .noRegistration), expected: .loginViaEmail(email: email)),
+            (
+                config: .make(domainRedirect: .noRegistration),
+                expected: .loginViaEmail(
+                    email: email,
+                    didDetectDomainConflict: false
+                )
+            ),
             (
                 config: .make(domainRedirect: .sso, ssoCodeString: someSSO.uuidString),
                 expected: .loginViaSSO(code: someSSO)
@@ -138,21 +148,6 @@ final class DetermineAuthMethodUseCaseTests: XCTestCase {
         }
     }
 
-    func testInvoke_withOnPremEmail_whenCloudAccountExists() async throws {
-        // given
-        mockAuthenticationAPI.getDomainRegistrationForEmail_MockValue = .make(
-            domainRedirect: .none,
-            isCloudAccountAlreadyRegistered: true
-        )
-
-        // when, then
-        await XCTAssertThrowsErrorAsync(
-            DetermineAuthMethodUseCaseFailure.onPremNotPossible(recovery: .loginViaEmail(email: "user@example.com"))
-        ) { [self] in
-            _ = try await sut.invoke(emailOrSSOCode: "user@example.com")
-        }
-    }
-
     func testInvoke_mapsErrors() async throws {
         // given
         let noInternetError = URLError(.notConnectedToInternet)
diff --git a/WireAuthentication/Tests/WireAuthenticationUITests/LoginViaEmail/LoginViaEmailViewModelTests.swift b/WireAuthentication/Tests/WireAuthenticationUITests/LoginViaEmail/LoginViaEmailViewModelTests.swift
index 6347d860334..6d487ab0851 100644
--- a/WireAuthentication/Tests/WireAuthenticationUITests/LoginViaEmail/LoginViaEmailViewModelTests.swift
+++ b/WireAuthentication/Tests/WireAuthenticationUITests/LoginViaEmail/LoginViaEmailViewModelTests.swift
@@ -51,6 +51,7 @@ class LoginViaEmailViewModelTests: XCTestCase {
             accountsURL: URL(string: "https://www.example.com")!,
             passwordValidator: passwordValidator,
             canCreateAccount: true,
+            didDetectDomainConflict: false,
             onCreateAccount: { [self] in onCreateAccountCalled = true }
         )
 
@@ -104,7 +105,8 @@ class LoginViaEmailViewModelTests: XCTestCase {
             RootView.ModalDestination.noHistory(
                 userID: Fixture.someAccessToken.userID,
                 cookies: [Fixture.someCookie],
-                accessToken: Fixture.someAccessToken
+                accessToken: Fixture.someAccessToken,
+                didDetectDomainConflict: false
             )
         )
     }
diff --git a/WireAuthentication/Tests/WireAuthenticationUITests/LoginViaEmailViewTests.swift b/WireAuthentication/Tests/WireAuthenticationUITests/LoginViaEmailViewTests.swift
index 841737cb830..9b9abc3fb18 100644
--- a/WireAuthentication/Tests/WireAuthenticationUITests/LoginViaEmailViewTests.swift
+++ b/WireAuthentication/Tests/WireAuthenticationUITests/LoginViaEmailViewTests.swift
@@ -39,8 +39,12 @@ class LoginViaEmailViewTests: XCTestCase {
     func testColorSchemeVariantsWithCreateAccount() {
         let screenBounds = UIScreen.main.bounds
 
-        let view = MockDependencies().loginViaEmailView(email: "foo@bar.com", canCreateAccount: true)
-            .frame(width: screenBounds.width, height: screenBounds.height)
+        let view = MockDependencies().loginViaEmailView(
+            email: "foo@bar.com",
+            canCreateAccount: true,
+            didDetectDomainConflict: false
+        )
+        .frame(width: screenBounds.width, height: screenBounds.height)
 
         snapshotHelper
             .withUserInterfaceStyle(.light)
@@ -54,8 +58,12 @@ class LoginViaEmailViewTests: XCTestCase {
     func testDynamicTypeVariantsWithCreateAccount() {
         let screenBounds = UIScreen.main.bounds
 
-        let view = MockDependencies().loginViaEmailView(email: "foo@bar.com", canCreateAccount: true)
-            .frame(width: screenBounds.width, height: screenBounds.height)
+        let view = MockDependencies().loginViaEmailView(
+            email: "foo@bar.com",
+            canCreateAccount: true,
+            didDetectDomainConflict: false
+        )
+        .frame(width: screenBounds.width, height: screenBounds.height)
 
         for dynamicTypeSize in DynamicTypeSize.allCases {
             snapshotHelper
@@ -70,8 +78,12 @@ class LoginViaEmailViewTests: XCTestCase {
     func testColorSchemeVariantsWithoutCreateAccount() {
         let screenBounds = UIScreen.main.bounds
 
-        let view = MockDependencies().loginViaEmailView(email: "foo@bar.com", canCreateAccount: false)
-            .frame(width: screenBounds.width, height: screenBounds.height)
+        let view = MockDependencies().loginViaEmailView(
+            email: "foo@bar.com",
+            canCreateAccount: false,
+            didDetectDomainConflict: false
+        )
+        .frame(width: screenBounds.width, height: screenBounds.height)
 
         snapshotHelper
             .withUserInterfaceStyle(.light)
@@ -85,8 +97,12 @@ class LoginViaEmailViewTests: XCTestCase {
     func testDynamicTypeVariantsWithoutCreateAccount() {
         let screenBounds = UIScreen.main.bounds
 
-        let view = MockDependencies().loginViaEmailView(email: "foo@bar.com", canCreateAccount: false)
-            .frame(width: screenBounds.width, height: screenBounds.height)
+        let view = MockDependencies().loginViaEmailView(
+            email: "foo@bar.com",
+            canCreateAccount: false,
+            didDetectDomainConflict: false
+        )
+        .frame(width: screenBounds.width, height: screenBounds.height)
 
         for dynamicTypeSize in DynamicTypeSize.allCases {
             snapshotHelper
diff --git a/WireAuthentication/Tests/WireAuthenticationUITests/NoHistoryViewTests.swift b/WireAuthentication/Tests/WireAuthenticationUITests/NoHistoryViewTests.swift
index 88fb84d117e..279f66a5529 100644
--- a/WireAuthentication/Tests/WireAuthenticationUITests/NoHistoryViewTests.swift
+++ b/WireAuthentication/Tests/WireAuthenticationUITests/NoHistoryViewTests.swift
@@ -41,7 +41,15 @@ class NoHistoryViewTests: XCTestCase {
     func testColorSchemeVariantsEmptyState() {
         let screenBounds = UIScreen.main.bounds
 
-        let viewModel = NoHistoryViewModel(userID: UUID(), cookies: [], accessToken: nil, onFlowCompletion: { _ in })
+        let viewModel = NoHistoryViewModel(
+            userID: UUID(),
+            cookies: [],
+            accessToken: nil,
+            didDetectDomainConflict: false,
+            howToChangeEmailURL: URL(string: "https://wire.com")!,
+            howToDeleteAccountURL: URL(string: "https://wire.com")!,
+            onFlowCompletion: { _ in }
+        )
         let view = NoHistoryView(viewModel: viewModel)
             .frame(width: screenBounds.width, height: screenBounds.height)
 
@@ -57,7 +65,15 @@ class NoHistoryViewTests: XCTestCase {
     func testDynamicTypeVariantsEmptyState() {
         let screenBounds = UIScreen.main.bounds
 
-        let viewModel = NoHistoryViewModel(userID: UUID(), cookies: [], accessToken: nil, onFlowCompletion: { _ in })
+        let viewModel = NoHistoryViewModel(
+            userID: UUID(),
+            cookies: [],
+            accessToken: nil,
+            didDetectDomainConflict: false,
+            howToChangeEmailURL: URL(string: "https://wire.com")!,
+            howToDeleteAccountURL: URL(string: "https://wire.com")!,
+            onFlowCompletion: { _ in }
+        )
         let view = NoHistoryView(viewModel: viewModel)
             .frame(width: screenBounds.width, height: screenBounds.height)
 
diff --git a/WireAuthentication/Tests/WireAuthenticationUITests/VerificationCode/VerificationCodeViewModelTests.swift b/WireAuthentication/Tests/WireAuthenticationUITests/VerificationCode/VerificationCodeViewModelTests.swift
index 1bb01f942b4..19a64a011b1 100644
--- a/WireAuthentication/Tests/WireAuthenticationUITests/VerificationCode/VerificationCodeViewModelTests.swift
+++ b/WireAuthentication/Tests/WireAuthenticationUITests/VerificationCode/VerificationCodeViewModelTests.swift
@@ -45,7 +45,8 @@ final class VerificationCodeViewModelTests {
             loginViaEmailUseCase: loginViaEmailUseCase,
             requestLoginVerificationCodeUseCase: requestLoginVerificationCodeUseCase,
             router: router,
-            numberOfDigits: 3 // Lets use a 3 digit code for simplicity
+            numberOfDigits: 3, // Lets use a 3 digit code for simplicity
+            didDetectDomainConflict: false
         )
 
         sut.$isLoading.dropFirst().sink { [self] in isLoadingCalls.append($0) }.store(in: &cancellables)
@@ -107,7 +108,8 @@ final class VerificationCodeViewModelTests {
                 RootView.ModalDestination.noHistory(
                     userID: Fixture.someAccessToken.userID,
                     cookies: [Fixture.someCookie],
-                    accessToken: Fixture.someAccessToken
+                    accessToken: Fixture.someAccessToken,
+                    didDetectDomainConflict: false
                 )
         )
     }
diff --git a/wire-ios-build-assets b/wire-ios-build-assets
index 58e13e7e38f..6804175aa4a 160000
--- a/wire-ios-build-assets
+++ b/wire-ios-build-assets
@@ -1 +1 @@
-Subproject commit 58e13e7e38f79dafdfade88a30d95314210fca5d
+Subproject commit 6804175aa4a6695466a49f3391171b87ece7de2c
diff --git a/wire-ios/Configuration/url.json b/wire-ios/Configuration/url.json
index 8027c0219a2..d3bd43e852d 100644
--- a/wire-ios/Configuration/url.json
+++ b/wire-ios/Configuration/url.json
@@ -19,5 +19,7 @@
     "mlsInfo": "https://support.wire.com/hc/articles/12434725011485-Messaging-Layer-Security-MLS-",
     "endToEndIdentityInfo": "https://support.wire.com/hc/articles/9211300150685-End-to-end-identity",
     "howToAddConversationToYourFavourites": "https://support.wire.com/hc/en-us/articles/360002855557-Add-a-conversation-to-your-favourites-folder",
-    "howToAddConversationToCustomFolder": "https://support.wire.com/hc/en-us/articles/360002855817-Add-a-conversation-to-a-custom-folder"
+    "howToAddConversationToCustomFolder": "https://support.wire.com/hc/en-us/articles/360002855817-Add-a-conversation-to-a-custom-folder",
+    "howToChangeEmail": "https://support.wire.com/hc/en-us/articles/203762940-Change-your-email-address",
+    "howToDeleteAccount": "https://support.wire.com/hc/en-us/articles/207555795-Delete-a-personal-account"
 }
diff --git a/wire-ios/Wire-iOS/Sources/Authentication/AuthenticationInterfaceBuilder.swift b/wire-ios/Wire-iOS/Sources/Authentication/AuthenticationInterfaceBuilder.swift
index 3c34aab1a8d..a053914a892 100644
--- a/wire-ios/Wire-iOS/Sources/Authentication/AuthenticationInterfaceBuilder.swift
+++ b/wire-ios/Wire-iOS/Sources/Authentication/AuthenticationInterfaceBuilder.swift
@@ -97,6 +97,8 @@ final class AuthenticationInterfaceBuilder {
                 minTLSVersion: TLSVersion.minVersionFrom(SecurityFlags.minTLSVersion.stringValue),
                 defaultAPIVersion: .v8,
                 accountsURL: environment.accountsURL,
+                howToChangeEmailURL: WireURLs.shared.howToChangeEmail,
+                howToDeleteAccountURL: WireURLs.shared.howToDeleteAccount,
                 passwordValidator: AuthenticationPasswordValidator(),
                 ssoCallbackURLScheme: Bundle.ssoURLScheme ?? "wire-sso",
                 userDefaults: .shared(),
diff --git a/wire-ios/Wire-iOS/Sources/Helpers/Bundle/Bundle+WireURLs.swift b/wire-ios/Wire-iOS/Sources/Helpers/Bundle/Bundle+WireURLs.swift
index 3ac9245d362..d36ed8b25f3 100644
--- a/wire-ios/Wire-iOS/Sources/Helpers/Bundle/Bundle+WireURLs.swift
+++ b/wire-ios/Wire-iOS/Sources/Helpers/Bundle/Bundle+WireURLs.swift
@@ -94,6 +94,12 @@ struct WireURLs: Codable {
     /// Link to an article explaining how to add a conversation to a custom folder.
     let howToAddConversationToCustomFolder: URL
 
+    /// Link to an article explaining how to change email address.
+    let howToChangeEmail: URL
+
+    /// Link to an article explaining how to delete a private account.
+    let howToDeleteAccount: URL
+
     static var shared: WireURLs = {
         do {
             return try WireURLs(forResource: "url", withExtension: "json")
@@ -132,6 +138,8 @@ struct WireURLs: Codable {
         case endToEndIdentityInfo
         case howToAddConversationToYourFavourites
         case howToAddConversationToCustomFolder
+        case howToChangeEmail
+        case howToDeleteAccount
     }
 
     enum WireURLsError: Error {


Reviews:
user: login: dmitrysimkin
body: 👍 
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T09:16:55Z
user: login: johnxnguyen
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-04T10:07:47Z
user: login: samwyndham
body: Nice work!
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-04T10:28:11Z

Review comments:
diff_hunk: @@ -95,10 +95,16 @@ class DetermineAuthMethodComponent: Component<DetermineAuthMethodComponentDepend
 
 extension DetermineAuthMethodComponent: DetermineAuthMethodView.Factory {
 
-    func loginViaEmailView(email: String, canCreateAccount: Bool) -> LoginViaEmailView {
+    @MainActor
+    func loginViaEmailView(
+        email: String,
+        canCreateAccount: Bool,
+        emailConflictWithCloudAccount: Bool
path: WireAuthentication/Sources/WireAuthentication/Components/DetermineAuthMethodComponent.swift
user: login: johnxnguyen
body: suggestion for here and elsewhere: `didDetectDomainConflict`
created_at: 2025-03-04T10:00:47Z
author_association: COLLABORATOR
diff_hunk: @@ -83,13 +83,15 @@ package struct DetermineAuthMethodUseCase: DetermineAuthMethodUseCaseProtocol {
 
         switch configuration.domainRedirect {
         case .none where configuration.isCloudAccountAlreadyRegistered == true:
-            throw DetermineAuthMethodUseCaseFailure.onPremNotPossible(recovery: .loginViaEmail(email: email))
+            // The email domain has been claimed by an on-prem backend,
path: WireAuthentication/Sources/WireAuthenticationLogic/DetermineAuthMethodUseCase.swift
user: login: johnxnguyen
body: praise: thanks for this comment
created_at: 2025-03-04T10:04:51Z
author_association: COLLABORATOR
diff_hunk: @@ -52,19 +57,55 @@ package struct NoHistoryView: View {
                 .wireButtonStyle(.primary)
                 .bold()
         }
+        .alert(
+            item: $viewModel.alert,
+            title: titleForAlert,
+            message: messageForAlert,
+            actions: { _ in
+                Button(L10n.Authentication.Error.howToChangeEmail, action: {
+                    viewModel.howToChangeEmail()
+                })
+                Button(L10n.Authentication.Error.howToDeleteAccount, action: {
+                    viewModel.howToDeleteAccount()
+                })
+                Button(L10n.Authentication.Error.confirm, action: {})
+            }
+        )
+        .onAppear {
+            if viewModel.emailConflictWithCloudAccount {
+                viewModel.alert = .cloudAccountAlreadyRegistered
+            }
path: WireAuthentication/Sources/WireAuthenticationUI/Views/Login/NoHistory/NoHistoryView.swift
user: login: samwyndham
body: **suggestion:** In my opinion we should put as much logic as possible into the view model to ensure testability. Rather then this approach you could add a method on appear to the view model and call it here:

```swift
// Inside view model

func onAppear() {
    if viewModel.emailConflictWithCloudAccount {
        alert = .cloudAccountAlreadyRegistered
    }
}
```
created_at: 2025-03-04T10:25:11Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-04T08:44:46Z
body: ## Test Results
    2 files      5 suites   1m 55s ⏱️
1 851 tests 1 825 ✅ 26 💤 0 ❌
1 861 runs  1 835 ✅ 26 💤 0 ❌

Results for commit 08f83991.

[test-results]:data:application/gzip;base64,H4sIAIsJyGcC/03MSw6DIBSF4a0Yxh14uaDYzTSAkJCqNDxGTfdepFYZ/t9JzptYt5hI7h29dSRml2rwEnMOMjm/lQTYoUxpH0Fw+OcjZq2rUX7Z0732x+EUK91SpD/BhODDISFvv9sBjrpekZ/UnFZoPmu3l9qvq0slSC+swGkCxhgKRc0MFoUdmEaOUio0Sslx7C35fAHqby1JCwEAAA==

:recycle: This comment has been updated with latest results.
author_association: CONTRIBUTOR
user: login: datadog-wireapp[bot]
created_at: 2025-03-04T08:47:06Z
body: 
## Datadog Report

Branch report: [`feat/email-already-in-use-alert-WPB-15936`](https://app.datadoghq.eu/ci/test-branch/github.com%2Fwireapp%2Fwire-ios/wire-ios-mono/feat%2Femail-already-in-use-alert-WPB-15936?env=ci&index=citest&_user_click_origin_=github)
Commit report: [`b07e7e5`](https://app.datadoghq.eu/ci/test-commit/github.com%2Fwireapp%2Fwire-ios/wire-ios-mono/feat%2Femail-already-in-use-alert-WPB-15936/b07e7e521ec0ca65eb03b7f702dd65b5f47e8ddf?env=ci&index=citest&_user_click_origin_=github)
Test service: `wire-ios-mono`

:white_check_mark: 0 Failed, 1744 Passed, 26 Skipped, 1m 48.3s Total Time




author_association: NONE