Skip to content

Conversation

@printminion-co
Copy link

@printminion-co printminion-co commented Dec 18, 2025

This PR implements a comprehensive, provider-agnostic mail account management system that replaces the legacy IONOS-specific implementation with a flexible, pluggable architecture.

Overview

The new provider system introduces a clean abstraction layer that allows external mail services (like IONOS Nextcloud Workspace Mail) to integrate seamlessly with the Nextcloud Mail app through a well-defined interface. The IONOS implementation has been refactored to use this new system while keeping all IONOS-specific code isolated in a dedicated namespace.

Key Features

🏗️ Provider Architecture

  • New Interfaces: IMailAccountProvider and IProviderCapabilities define the contract for external mail account providers
  • Registry Service: ProviderRegistryService manages provider registration and lifecycle
  • Business Logic Layer: AccountProviderService handles provider-specific operations
  • Controller: ExternalAccountsController exposes REST API endpoints for provider operations

🔌 IONOS Provider Implementation

  • Full reimplementation using the provider system
  • All IONOS code relocated to lib/Provider/MailAccountProvider/Implementations/Ionos/
  • Services organized under provider namespace for better isolation
  • Comprehensive facade pattern (IonosProviderFacade) for clean architecture

🖥️ Frontend Integration

  • Generic ExternalProviderTab component replaces IONOS-specific UI
  • App password management UI (ProviderAppPassword.vue) for password reset with generate/copy functionality
  • Retry logic for IMAP connections with progressive user feedback and exponential backoff (3 retries with 2-3s, 4-6s delays)
  • Provider availability automatically detected and UI shown conditionally

⚙️ OCC Commands

  • mail:provider:list - List all registered providers
  • mail:provider:status - Check provider availability for user
  • mail:provider:create-account - Create mail account via provider
  • mail:provider:generate-password - Generate new app password

Full documentation available in doc/provider-commands.md

🔐 App Password Management

  • New API endpoint: POST /api/providers/{providerId}/password
  • supportsAppPasswordGeneration capability declaration
  • generateAppPassword() interface method
  • Frontend UI integrated into AccountSettings.vue

Technical Changes

Architecture Improvements

  • Namespace reorganization: DTOs moved to Common namespace for reusability
  • Dependency injection: Full DI support through Nextcloud's container
  • Error handling: New ProviderServiceException for provider-specific errors
  • Lifecycle integration: Provider cleanup on user deletion via UserDeletedListener

API Changes

  • Account creation response now includes provider metadata
  • Account serialization includes provider information in PageController
  • Removed legacy /api/ionos/* routes (superseded by provider system)

Code Quality

  • Comprehensive test coverage: 6,000+ new lines of unit tests across all components
  • Type safety: Strict typing throughout with declare(strict_types=1)
  • Documentation: README and command documentation for developer onboarding

Removed/Deprecated

  • IonosAccountsController (replaced by ExternalAccountsController)
  • IonosServiceException (replaced by ProviderServiceException)
  • ❌ Legacy IONOS routes in routes.php
  • NewEmailAddressTab.vue (replaced by ExternalProviderTab.vue)

Migration Notes

The new system is backward compatible - existing IONOS accounts continue to work. The IONOS implementation has been internally refactored but maintains the same external behavior with enhanced capabilities:

  • App password reset now available
  • Better error handling and retry logic
  • Improved user feedback during account creation

Files Changed

  • 68 files changed
  • +7,193 insertions / -937 deletions
  • New files: 43 (provider system, commands, tests, docs)
  • Removed files: 4 (legacy IONOS implementation)
  • Refactored files: 21 (namespace changes, integration updates)

Testing

All changes are covered by comprehensive unit tests:

  • Provider system core: ProviderRegistryServiceTest, AccountProviderServiceTest
  • IONOS implementation: IonosProviderTest, IonosProviderFacadeTest
  • Commands: Full test suite for all 4 OCC commands
  • Controllers: ExternalAccountsControllerTest (602 lines)
  • Services: Query/Mutation service tests with extensive mocking

This refactoring provides a solid foundation for adding additional mail providers in the future while maintaining clean separation of concerns and minimal impact on the core Mail app functionality.

…ovider system

Add provider system with IMailAccountProvider interface, ProviderRegistryService,
and ExternalAccountsController. Includes ProviderCapabilities for declaring
provider features, AccountProviderService for business logic, and comprehensive
unit tests.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
Relocate MailAccountConfig and MailServerConfig from lib/Service/IONOS/Dto
to lib/Provider/MailAccountProvider/Common/Dto to make them reusable by
multiple providers. Update imports in consuming classes and move unit tests.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…d cleanup integration

Add AccountProviderService to PageController to expose mail-providers-available
config to frontend. Integrate ProviderRegistryService into UserDeletedListener
for provider-managed account cleanup. Update unit tests.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…r for mail config availability check

Refactor IonosMailConfigService.isMailConfigAvailable to accept optional
user ID parameter. Add unit tests to verify behavior with explicit user IDs.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
@printminion-co printminion-co force-pushed the mk/dev/ionosmail_get_app_password branch from e75efc8 to 39cc274 Compare December 30, 2025 17:33
@printminion-co printminion-co changed the title ionosmail get app password ionosmail get app password + External Mail Account Provider System Implementation Dec 30, 2025
@printminion-co printminion-co force-pushed the mk/dev/ionosmail_get_app_password branch from 39cc274 to 32f8d27 Compare December 30, 2025 17:46
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a comprehensive, provider-agnostic mail account management system that replaces the legacy IONOS-specific implementation with a flexible, pluggable architecture. The new system introduces clean abstraction layers allowing external mail services (like IONOS Nextcloud Workspace Mail) to integrate seamlessly through well-defined interfaces.

Key Changes

  • Provider Architecture: New interfaces (IMailAccountProvider, IProviderCapabilities) with registry service for managing providers
  • IONOS Provider Refactoring: Full reimplementation using the provider system with code relocated to dedicated namespace
  • Frontend Integration: Generic ExternalProviderTab component with app password management UI and retry logic
  • OCC Commands: Four new commands for provider management (list, status, create-account, generate-password)

Reviewed changes

Copilot reviewed 68 out of 68 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Unit/Service/AccountServiceTest.php Updated to use ProviderRegistryService instead of IonosAccountDeletionService
tests/Unit/Service/AccountProviderServiceTest.php New test suite for provider metadata service
tests/Unit/Provider/MailAccountProvider/ProviderRegistryServiceTest.php Comprehensive tests for provider registry
tests/Unit/Provider/MailAccountProvider/Implementations/IonosProviderTest.php Tests for IONOS provider implementation
tests/Unit/Provider/MailAccountProvider/Implementations/Ionos/IonosProviderFacadeTest.php Tests for IONOS facade pattern
tests/Unit/Controller/ExternalAccountsControllerTest.php Tests for generic provider controller (602 lines)
tests/Unit/Command/Provider*.php Test suites for all 4 OCC commands
lib/Provider/MailAccountProvider/*.php Core provider system interfaces and implementations
lib/Service/AccountProviderService.php Business logic for provider metadata
src/components/ExternalProviderTab.vue Generic provider UI with retry logic
src/components/ProviderAppPassword.vue App password management component

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bromiesTM bromiesTM self-requested a review January 6, 2026 10:13
Copy link

@bromiesTM bromiesTM left a comment

Choose a reason for hiding this comment

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

provisional ok but lets discuss whether we need translations for a release

printminion-co and others added 18 commits January 9, 2026 10:32
…e Mail account provider

Add IonosProvider implementation with IonosProviderFacade, IonosAccountMutationService,
and IonosAccountQueryService. Includes comprehensive unit tests for all components.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…ication bootstrap

Register IonosProvider in Application.boot() with exception handling and logging.
Add unit tests for constructor, provider registration flow, and error handling.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…mponent

Add ExternalProviderTab component to replace IONOS-specific NewEmailAddressTab
with provider-agnostic implementation. Update AccountForm.vue to use new component.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
Remove IonosAccountsController, IonosServiceException, and related routes.
These are superseded by the provider system. Update tests and remove obsolete code.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…r namespace

Relocate all IONOS services from lib/Service/IONOS to
lib/Provider/MailAccountProvider/Implementations/Ionos/Service.
Update namespace declarations and imports in consuming classes.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…n during account creation

Implement progressive user feedback and retry mechanism in ExternalProviderTab.
Retry mailbox fetch 3 times with exponential backoff and jitter (2-3s, 4-6s).
Show clear status messages during each phase. Redirect after max retries with
message about delayed sync.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…provider management

Add ProviderCommandBase, ProviderList, ProviderStatus, ProviderCreateAccount,
and ProviderDeleteAccount commands with full parameter validation, error handling,
and comprehensive unit tests.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…o.xml

Register ProviderList, ProviderStatus, ProviderCreateAccount,
ProviderGenerateAppPassword, and ProviderDeleteAccount in info.xml.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…ords for external accounts

Add ExternalAccountsController.generatePassword() endpoint with route
/api/providers/{providerId}/password. Add IProviderCapabilities.supportsAppPasswordGeneration
and IMailAccountProvider.generateAppPassword(). Update README with documentation.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…e Mail app password reset

Implement IonosProvider.generateAppPassword() using IonosProviderFacade.generateAppPassword()
which calls IonosAccountMutationService.resetPassword(). Add comprehensive unit tests.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…rovider app password generation

Add ProviderGenerateAppPassword command with full parameter validation and
comprehensive unit tests.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…ord command in info.xml

Register ProviderGenerateAppPassword in info.xml.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…s documentation

Add doc/provider-commands.md with usage, parameters, examples, workflows,
troubleshooting, and testing instructions for all provider management commands.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…property to readonly in PageController

Make PageController.accountProviderService readonly and add provider metadata
to serialized account data. Update unit tests.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…ponse with provider metadata

Updated the ExternalAccountsController to include provider metadata in the account creation response. This change improves the information returned to the client, facilitating better integration with the account provider service.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
…ider-managed accounts

Add ProviderPasswordService.js for API calls, ProviderAppPassword.vue component
for password reset UI with generate/copy functionality. Integrate into
AccountSettings.vue for provider-managed accounts with app password support.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
@printminion-co printminion-co force-pushed the mk/dev/ionosmail_get_app_password branch from dd0352f to 6c32a2b Compare January 9, 2026 09:33
…Service

Replace manual directory traversal with dirname() function for better readability and maintainability when constructing public_suffix_list.dat path.

Signed-off-by: Misha M.-Kupriyanov <[email protected]>
@printminion-co printminion-co force-pushed the mk/dev/ionosmail_get_app_password branch from 6c32a2b to 9682525 Compare January 9, 2026 09:35
@printminion-co printminion-co requested a review from Copilot January 9, 2026 09:35
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 84 out of 84 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@printminion-co printminion-co merged commit da04710 into ionos-dev Jan 9, 2026
18 of 27 checks passed
@printminion-co printminion-co deleted the mk/dev/ionosmail_get_app_password branch January 9, 2026 09:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants