Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9d5c248
IONOS(ionos-mail): stub for new email creation form
Arsalanulhaq Sep 23, 2025
305f771
IONOS(ionos-mail): update stub for new email creation php Implementation
Arsalanulhaq Oct 8, 2025
b7deeca
IONOS(ionos-mail): Add IONOS Mail API client to composer.json
printminion-co Sep 23, 2025
175e391
IONOS(ionos-mail): replace instance methods with direct calls for tra…
printminion-co Oct 15, 2025
82eac6d
IONOS(ionos-mail): remove password field from new email creation form
printminion-co Oct 14, 2025
6a4ef69
IONOS(ionos-mail): unify feedback clearing methods in email form
printminion-co Oct 15, 2025
0a40a0e
IONOS(ionos-mail): add feedback clearing on email input change
printminion-co Oct 15, 2025
e0b6f69
IONOS(ionos-mail): cleanup host info on account creation to improve i…
printminion-co Oct 15, 2025
b74daa8
IONOS(ionos-mail): add support for IONOS mail configuration in accoun…
printminion-co Oct 14, 2025
aa261a2
IONOS(ionos-mail): update email account creation to remove account na…
printminion-co Oct 14, 2025
bfc3d1e
IONOS(ionos-mail): refactor email account creation to streamline resp…
printminion-co Oct 14, 2025
2ae5ae0
IONOS(ionos-mail): improve error handling in email account creation
printminion-co Oct 15, 2025
8bbbe27
IONOS(ionos-mail): refine error handling for account creation feedback
printminion-co Oct 15, 2025
22cc49d
IONOS(ionos-mail): refactor rename API call methods for email account…
printminion-co Oct 23, 2025
a72e2eb
IONOS(ionos-mail): refactor: extract IonosMailService for email accou…
printminion-co Oct 23, 2025
da90d70
IONOS(ionos-mail): integrate IONOS API client for email account manag…
printminion-co Oct 23, 2025
13b8c0a
IONOS(ionos-mail): simplify email account creation by removing error …
printminion-co Oct 27, 2025
c8081d3
IONOS(ionos-mail): add data transfer objects for mail account and ser…
printminion-co Oct 27, 2025
de64067
IONOS(ionos-mail): Update IONOS Mail API client to 2.0.0-6ebd22a
printminion-co Oct 27, 2025
a344cd1
IONOS(ionos-mail): enhance email account creation with improved error…
printminion-co Oct 27, 2025
43e8515
IONOS(ionos-mail): add SSL mode normalization for API response values
printminion-co Oct 28, 2025
50add3b
IONOS(ionos-mail): enhance error handling by adding status code to se…
printminion-co Oct 28, 2025
40c0c85
IONOS(ionos-mail): add domain preference for IONOS mail configuration
printminion-co Oct 23, 2025
c2fa764
IONOS(ionos-mail): fix isValidEmail check
printminion-co Oct 29, 2025
f71de88
IONOS(ionos-mail): refactor email account creation to use config serv…
printminion-co Oct 29, 2025
eeb2645
IONOS(ionos-mail): simplify success response by removing email addres…
printminion-co Oct 30, 2025
0b261cf
IONOS(ionos-mail): refactor email input handling to separate user and…
printminion-co Oct 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@
'url' => '/api/tags',
'verb' => 'POST'
],
[
'name' => 'ionosAccounts#create',
'url' => '/api/ionos/accounts',
'verb' => 'POST'
],
[
'name' => 'tags#update',
'url' => '/api/tags/{id}',
Expand Down
20 changes: 20 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"glenscott/url-normalizer": "^1.4",
"gravatarphp/gravatar": "dev-master#6b9f6a45477ce48285738d9d0c3f0dbf97abe263",
"hamza221/html2text": "^1.0",
"ionos-productivity/ionos-mail-configuration-api-client": "2.0.0",
"jeremykendall/php-domain-parser": "^6.4.0",
"nextcloud/horde-managesieve": "^1.0",
"nextcloud/horde-smtp": "^1.0.2",
Expand All @@ -44,6 +45,25 @@
"wamania/php-stemmer": "4.0 as 3.0",
"youthweb/urllinker": "^2.1.0"
},
"repositories": [
{
"type": "package",
"package": {
"name": "ionos-productivity/ionos-mail-configuration-api-client",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/ionos-productivity/ionos-mail-configuration-api-client.git",
"reference": "2.0.0-6ebd22a"
},
"autoload": {
"psr-4": {
"IONOS\\MailConfigurationAPI\\Client\\" : "lib/"
}
}
}
}
],
"provide": {
"psr/log": "^1.0.4|^2|^3"
},
Expand Down
19 changes: 17 additions & 2 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

95 changes: 95 additions & 0 deletions lib/Controller/IonosAccountsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 STRATO GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Mail\Controller;

use OCA\Mail\Exception\ServiceException;
use OCA\Mail\Http\JsonResponse as MailJsonResponse;
use OCA\Mail\Http\TrapError;
use OCA\Mail\Service\IONOS\Dto\MailAccountConfig;
use OCA\Mail\Service\IONOS\IonosMailService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\Attribute\OpenAPI;
use OCP\AppFramework\Http\JSONResponse;
use OCP\IRequest;
use Psr\Log\LoggerInterface;

#[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)]
class IonosAccountsController extends Controller {

// Error message constants
private const ERR_ALL_FIELDS_REQUIRED = 'All fields are required';
private const ERR_CREATE_EMAIL_FAILED = 'Failed to create email account';
private const ERR_IONOS_API_ERROR = 'IONOS_API_ERROR';

public function __construct(
string $appName,
IRequest $request,
private IonosMailService $ionosMailService,
private AccountsController $accountsController,
private LoggerInterface $logger,
) {
parent::__construct($appName, $request);
}

// Helper: input validation
private function validateInput(string $accountName, string $emailUser): ?JSONResponse {
if ($accountName === '' || $emailUser === '') {
return new JSONResponse(['success' => false, 'message' => self::ERR_ALL_FIELDS_REQUIRED, 'error' => self::ERR_IONOS_API_ERROR], 400);
}
return null;
}

/**
* @NoAdminRequired
*/
#[TrapError]
public function create(string $accountName, string $emailUser): JSONResponse {
if ($error = $this->validateInput($accountName, $emailUser)) {
return $error;
}

try {
$this->logger->info('Starting IONOS email account creation', [ 'emailAddress' => $emailUser, 'accountName' => $accountName ]);
$ionosResponse = $this->ionosMailService->createEmailAccount($emailUser);

$this->logger->info('IONOS email account created successfully', [ 'emailAddress' => $ionosResponse->getEmail() ]);
return $this->createNextcloudMailAccount($accountName, $ionosResponse);
} catch (ServiceException $e) {
$data = [
'error' => self::ERR_IONOS_API_ERROR,
'statusCode' => $e->getCode(),
];
$this->logger->error('IONOS service error: ' . $e->getMessage(), $data);

return MailJsonResponse::fail($data);
} catch (\Exception $e) {
return MailJsonResponse::error('Could not create account');
}
}

private function createNextcloudMailAccount(string $accountName, MailAccountConfig $mailConfig): JSONResponse {
$imap = $mailConfig->getImap();
$smtp = $mailConfig->getSmtp();

return $this->accountsController->create(
$accountName,
$mailConfig->getEmail(),
$imap->getHost(),
$imap->getPort(),
$imap->getSecurity(),
$imap->getUsername(),
$imap->getPassword(),
$smtp->getHost(),
$smtp->getPort(),
$smtp->getSecurity(),
$smtp->getUsername(),
$smtp->getPassword(),
);
}
}
9 changes: 8 additions & 1 deletion lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use OCA\Mail\Service\AliasesService;
use OCA\Mail\Service\Classification\ClassificationSettingsService;
use OCA\Mail\Service\InternalAddressService;
use OCA\Mail\Service\IONOS\IonosConfigService;
use OCA\Mail\Service\OutboxService;
use OCA\Mail\Service\QuickActionsService;
use OCA\Mail\Service\SmimeService;
Expand Down Expand Up @@ -74,7 +75,8 @@ class PageController extends Controller {
private InternalAddressService $internalAddressService;
private QuickActionsService $quickActionsService;

public function __construct(string $appName,
public function __construct(
string $appName,
IRequest $request,
IURLGenerator $urlGenerator,
IConfig $config,
Expand All @@ -97,6 +99,7 @@ public function __construct(string $appName,
InternalAddressService $internalAddressService,
IAvailabilityCoordinator $availabilityCoordinator,
QuickActionsService $quickActionsService,
private IonosConfigService $ionosConfigService,
) {
parent::__construct($appName, $request);

Expand Down Expand Up @@ -208,8 +211,12 @@ public function index(): TemplateResponse {

$user = $this->userSession->getUser();
$response = new TemplateResponse($this->appName, 'index');


$this->initialStateService->provideInitialState('preferences', [
'attachment-size-limit' => $this->config->getSystemValue('app.mail.attachment-size-limit', 0),
'ionos-mailconfig-enabled' => $this->config->getAppValue('mail', 'ionos-mailconfig-enabled', 'no') === 'yes',
'ionos-mailconfig-domain' => $this->ionosConfigService->getMailDomain(),
'app-version' => $this->config->getAppValue('mail', 'installed_version'),
'external-avatars' => $this->preferences->getPreference($this->currentUserId, 'external-avatars', 'true'),
'layout-mode' => $this->preferences->getPreference($this->currentUserId, 'layout-mode', 'vertical-split'),
Expand Down
47 changes: 47 additions & 0 deletions lib/Service/IONOS/ApiMailConfigClientService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 STRATO GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
namespace OCA\Mail\Service\IONOS;

use GuzzleHttp\ClientInterface;
use IONOS\MailConfigurationAPI\Client\Api\MailConfigurationAPIApi;

class ApiMailConfigClientService {

/**
* Create a new client
*
* @param array $config
* @return ClientInterface
*/
public function newClient(array $config): ClientInterface {
return new \GuzzleHttp\Client($config);
}

/**
* Create a new EventAPIApi
*
* @param ClientInterface $client
* @param string $apiBaseUrl
* @return MailConfigurationAPIApi
*/
public function newEventAPIApi(ClientInterface $client, string $apiBaseUrl): MailConfigurationAPIApi {

if (empty($apiBaseUrl)) {
throw new \InvalidArgumentException('API base URL is required');
}

$apiClient = new MailConfigurationAPIApi(
$client,
);

$apiClient->getConfig()->setHost($apiBaseUrl);

return $apiClient;
}
}
47 changes: 47 additions & 0 deletions lib/Service/IONOS/Dto/MailAccountConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 STRATO GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Service\IONOS\Dto;

/**
* Data transfer object for complete mail account configuration
*/
class MailAccountConfig {
public function __construct(
private readonly string $email,
private readonly MailServerConfig $imap,
private readonly MailServerConfig $smtp,
) {
}

public function getEmail(): string {
return $this->email;
}

public function getImap(): MailServerConfig {
return $this->imap;
}

public function getSmtp(): MailServerConfig {
return $this->smtp;
}

/**
* Convert to array format for backwards compatibility
*
* @return array{email: string, imap: array, smtp: array}
*/
public function toArray(): array {
return [
'email' => $this->email,
'imap' => $this->imap->toArray(),
'smtp' => $this->smtp->toArray(),
];
}
}
59 changes: 59 additions & 0 deletions lib/Service/IONOS/Dto/MailServerConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2025 STRATO GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Mail\Service\IONOS\Dto;

/**
* Data transfer object for mail server configuration (IMAP/SMTP)
*/
class MailServerConfig {
public function __construct(
private readonly string $host,
private readonly int $port,
private readonly string $security,
private readonly string $username,
private readonly string $password,
) {
}

public function getHost(): string {
return $this->host;
}

public function getPort(): int {
return $this->port;
}

public function getSecurity(): string {
return $this->security;
}

public function getUsername(): string {
return $this->username;
}

public function getPassword(): string {
return $this->password;
}

/**
* Convert to array format for backwards compatibility
*
* @return array{host: string, port: int, security: string, username: string, password: string}
*/
public function toArray(): array {
return [
'host' => $this->host,
'port' => $this->port,
'security' => $this->security,
'username' => $this->username,
'password' => $this->password,
];
}
}
Loading
Loading