diff --git a/lib/Providers/Mail/Service.php b/lib/Providers/Mail/Service.php index 3edea6f..2bbb900 100644 --- a/lib/Providers/Mail/Service.php +++ b/lib/Providers/Mail/Service.php @@ -880,7 +880,31 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC ); } - $nativeMessage = $this->normalizeMessageProperties($message)->toJmap(); + $nativeProperties = $this->normalizeMessageProperties($message); + $attachments = $nativeProperties->getAttachments(); + foreach ($attachments as $attachment) { + if ($attachment->getBlobId() !== null) { + continue; + } + + $content = $attachment->getContent(); + if ($content === null) { + throw new \InvalidArgumentException(sprintf( + 'Attachment "%s" has neither content nor a JMAP blob identifier', + $attachment->getName() ?? 'unnamed', + )); + } + + $attachment->setBlobId($this->mailService->blobDeposit( + $attachment->getType() ?? 'application/octet-stream', + $content, + )); + } + if ($attachments !== []) { + $nativeProperties->setAttachments(...$attachments); + } + + $nativeMessage = $nativeProperties->toJmap(); $transportId = $this->mailService->entitySubmitFresh($identityId, $nativeMessage, $preSendTarget->collection(), $postSentTarget->collection()); return new EntitySubmitResult( diff --git a/lib/Service/Remote/RemoteMailService.php b/lib/Service/Remote/RemoteMailService.php index b9a81a6..7313951 100644 --- a/lib/Service/Remote/RemoteMailService.php +++ b/lib/Service/Remote/RemoteMailService.php @@ -929,6 +929,19 @@ class RemoteMailService { $submission->message('#' . $messageCreateId); $bundle = $this->dataStore->perform([$r0, $r1]); + $messageResponse = $bundle->response(0); + if ($messageResponse instanceof ResponseException) { + throw new Exception($messageResponse->type() . ': ' . $messageResponse->description(), 1); + } + if (method_exists($messageResponse, 'createFailure')) { + $failure = $messageResponse->createFailure($messageCreateId); + if (is_array($failure)) { + $type = $failure['type'] ?? 'unknownError'; + $description = $failure['description'] ?? 'Email creation failed'; + throw new Exception($type . ': ' . $description, 1); + } + } + $response = $bundle->response(1); if ($response instanceof ResponseException) { if ($response->type() === 'unknownMethod') { @@ -940,6 +953,18 @@ class RemoteMailService { return $this->extractSubmissionIdentifier($response, $submissionCreateId); } + /** + * Upload attachment content and return its JMAP blob identifier. + */ + public function blobDeposit(string $type, string $data): string { + $response = json_decode($this->dataStore->upload($this->dataAccount, $type, $data), true); + if (!is_array($response) || !isset($response['blobId']) || !is_string($response['blobId']) || $response['blobId'] === '') { + throw new Exception('JMAP attachment upload did not return a blob identifier', 1); + } + + return $response['blobId']; + } + /** * Submit an existing draft message. *