Skip to content

Commit ab08b5e

Browse files
feat: use task processing to send emails
Signed-off-by: SebastianKrupinski <[email protected]>
1 parent f1b7ac4 commit ab08b5e

File tree

4 files changed

+243
-1
lines changed

4 files changed

+243
-1
lines changed

lib/AppInfo/Application.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@
6868
use OCA\Mail\Service\UserPreferenceService;
6969
use OCA\Mail\SetupChecks\MailConnectionPerformance;
7070
use OCA\Mail\SetupChecks\MailTransport;
71+
use OCA\Mail\TaskProcessing\MailSendTask;
72+
use OCA\Mail\TaskProcessing\TaskProcessingProvider;
7173
use OCA\Mail\Vendor\Favicon\Favicon;
7274
use OCP\AppFramework\App;
7375
use OCP\AppFramework\Bootstrap\IBootContext;
@@ -164,6 +166,9 @@ public function register(IRegistrationContext $context): void {
164166
$context->registerSetupCheck(MailTransport::class);
165167
$context->registerSetupCheck(MailConnectionPerformance::class);
166168

169+
$context->registerTaskProcessingProvider(TaskProcessingProvider::class);
170+
$context->registerTaskProcessingTaskType(MailSendTask::class);
171+
167172
// bypass Horde Translation system
168173
Horde_Translation::setHandler('Horde_Imap_Client', new HordeTranslationHandler());
169174
Horde_Translation::setHandler('Horde_Mime', new HordeTranslationHandler());

lib/Provider/MailService.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@
88
*/
99
namespace OCA\Mail\Provider;
1010

11+
use OCA\Mail\AppInfo\Application;
1112
use OCA\Mail\Provider\Command\MessageSend;
13+
use OCA\Mail\TaskProcessing\MailSendTask;
1214
use OCP\Mail\Provider\Address;
1315
use OCP\Mail\Provider\Exception\SendException;
1416
use OCP\Mail\Provider\IAddress;
1517
use OCP\Mail\Provider\IMessage;
1618
use OCP\Mail\Provider\IMessageSend;
1719
use OCP\Mail\Provider\IService;
1820
use OCP\Mail\Provider\Message;
19-
21+
use OCP\TaskProcessing\IManager as TaskProcessingManager;
22+
use OCP\TaskProcessing\Task;
2023
use Psr\Container\ContainerInterface;
2124

2225
class MailService implements IService, IMessageSend {
@@ -184,6 +187,25 @@ public function initiateMessage(): IMessage {
184187
*/
185188
#[\Override]
186189
public function sendMessage(IMessage $message, array $options = []): void {
190+
$taskProcessingManager = $this->container->get(TaskProcessingManager::class);
191+
$availableTaskTypes = $taskProcessingManager->getAvailableTaskTypes();
192+
// if task processing is available use it
193+
if (isset($availableTaskTypes[MailSendTask::ID])) {
194+
$task = new Task(
195+
MailSendTask::ID,
196+
[
197+
'userId' => $this->userId,
198+
'serviceId' => $this->serviceId,
199+
'message' => $message,
200+
'options' => $options,
201+
],
202+
Application::APP_ID,
203+
null
204+
);
205+
$taskProcessingManager->scheduleTask($task);
206+
return;
207+
}
208+
// fallback to direct send
187209
/** @var MessageSend $cmd */
188210
$cmd = $this->container->get(MessageSend::class);
189211
// perform action
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Mail\TaskProcessing;
11+
12+
use OCA\Mail\Provider\Command\MessageSend;
13+
use OCP\IL10N;
14+
use OCP\Mail\Provider\Message;
15+
use OCP\TaskProcessing\EShapeType;
16+
use OCP\TaskProcessing\ISynchronousProvider;
17+
use OCP\TaskProcessing\ShapeDescriptor;
18+
use Psr\Container\ContainerInterface;
19+
20+
/**
21+
* This is the task processing provider for sending messages via the mail app.
22+
*
23+
* @since 5.6.0
24+
*/
25+
class MailSendProvider implements ISynchronousProvider {
26+
27+
public function __construct(
28+
private readonly ContainerInterface $container,
29+
private readonly IL10N $l,
30+
) { }
31+
32+
public function getId(): string {
33+
return 'mail:send';
34+
}
35+
36+
public function getName(): string {
37+
return 'Mail Send Provider';
38+
}
39+
40+
public function getTaskTypeId(): string {
41+
return 'mail:send';
42+
}
43+
44+
public function getExpectedRuntime(): int {
45+
return 60;
46+
}
47+
48+
public function getOptionalInputShape(): array {
49+
return [
50+
'userId' => new ShapeDescriptor(
51+
$this->l->t('User ID'),
52+
$this->l->t('The ID of the user sending the email'),
53+
EShapeType::Text
54+
),
55+
'serviceId' => new ShapeDescriptor(
56+
$this->l->t('Service ID'),
57+
$this->l->t('The ID of the service/account sending the email'),
58+
EShapeType::Number
59+
),
60+
'message' => new ShapeDescriptor(
61+
$this->l->t('Message'),
62+
$this->l->t('The email message to be sent (OCP\Mail\IMessage)'),
63+
EShapeType::Object
64+
),
65+
'options' => new ShapeDescriptor(
66+
$this->l->t('Options'),
67+
$this->l->t('Additional options for sending the email'),
68+
EShapeType::Array
69+
),
70+
];
71+
72+
}
73+
74+
public function getOptionalOutputShape(): array {
75+
return [];
76+
}
77+
78+
public function getInputShapeEnumValues(): array {
79+
return [];
80+
}
81+
82+
public function getInputShapeDefaults(): array {
83+
return [];
84+
}
85+
86+
public function getOptionalInputShapeEnumValues(): array {
87+
return [];
88+
}
89+
90+
public function getOptionalInputShapeDefaults(): array {
91+
return [];
92+
}
93+
94+
public function getOutputShapeEnumValues(): array {
95+
return [];
96+
}
97+
98+
public function getOptionalOutputShapeEnumValues(): array {
99+
return [];
100+
}
101+
102+
public function process(?string $userId, array $input, callable $reportProgress): array {
103+
// extract parameters
104+
$userId = $input['userId'] ?? null;
105+
$serviceId = $input['serviceId'] ?? null;
106+
$options = $input['options'] ?? [];
107+
if (isset($input['message'])) {
108+
$message = new Message();
109+
$message->jsonDeserialize((array)$input['message']);
110+
} else {
111+
$message = null;
112+
}
113+
// validate parameters
114+
if ($userId === null || empty($userId)) {
115+
throw new \InvalidArgumentException('Invalid or missing userId');
116+
}
117+
if ($serviceId === null || empty($serviceId) || $serviceId <= 0) {
118+
throw new \InvalidArgumentException('Invalid or missing serviceId');
119+
}
120+
if (!$message instanceof Message) {
121+
throw new \InvalidArgumentException('Invalid or missing message');
122+
}
123+
// perform task
124+
/** @var MessageSend $cmd */
125+
$cmd = $this->container->get(MessageSend::class);
126+
$cmd->perform($userId, (string)$serviceId, $message, $options);
127+
128+
return [];
129+
}
130+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Mail\TaskProcessing;
11+
12+
use OCP\IL10N;
13+
use OCP\L10N\IFactory;
14+
use OCP\TaskProcessing\EShapeType;
15+
use OCP\TaskProcessing\ITaskType;
16+
use OCP\TaskProcessing\ShapeDescriptor;
17+
18+
/**
19+
* This is the task processing task type for sending messages via the mail app.
20+
*
21+
* @since 5.6.0
22+
*/
23+
class MailSendTask implements ITaskType {
24+
25+
public const ID = 'mail:send';
26+
private IL10N $l;
27+
28+
public function __construct(
29+
private readonly IFactory $l10nFactory,
30+
) {
31+
$this->l = $l10nFactory->get('lib');
32+
}
33+
34+
public function getName(): string {
35+
return $this->l->t('Mail Send');
36+
}
37+
38+
public function getDescription(): string {
39+
return $this->l->t('Send an email using the mail app.');
40+
}
41+
42+
public function getId(): string {
43+
return self::ID;
44+
}
45+
46+
public function getInputShape(): array {
47+
return [
48+
'userId' => new ShapeDescriptor(
49+
$this->l->t('User ID'),
50+
$this->l->t('The ID of the user sending the email'),
51+
EShapeType::Text
52+
),
53+
'serviceId' => new ShapeDescriptor(
54+
$this->l->t('Service ID'),
55+
$this->l->t('The ID of the service/account sending the email'),
56+
EShapeType::Number
57+
),
58+
'message' => new ShapeDescriptor(
59+
$this->l->t('Message'),
60+
$this->l->t('The email message to be sent (OCP\Mail\IMessage)'),
61+
EShapeType::Object
62+
),
63+
'options' => new ShapeDescriptor(
64+
$this->l->t('Options'),
65+
$this->l->t('Additional options for sending the email'),
66+
EShapeType::Array
67+
),
68+
];
69+
}
70+
71+
public function getOutputShape(): array {
72+
return [
73+
'status_code' => new ShapeDescriptor(
74+
$this->l->t('Status Code'),
75+
$this->l->t('The status code of the email sending operation'),
76+
EShapeType::Number
77+
),
78+
'status_message' => new ShapeDescriptor(
79+
$this->l->t('Status Message'),
80+
$this->l->t('A message describing the result of the email sending operation'),
81+
EShapeType::Text
82+
),
83+
];
84+
}
85+
}

0 commit comments

Comments
 (0)