diff --git a/apps/settings/tests/Mailer/NewUserMailHelperTest.php b/apps/settings/tests/Mailer/NewUserMailHelperTest.php
index 19cfab8c19346..72af678f832e8 100644
--- a/apps/settings/tests/Mailer/NewUserMailHelperTest.php
+++ b/apps/settings/tests/Mailer/NewUserMailHelperTest.php
@@ -57,6 +57,8 @@ protected function setUp(): void {
$this->defaults,
$this->urlGenerator,
$this->l10nFactory,
+ null,
+ null,
'test.TestTemplate',
[]
);
diff --git a/apps/theming/lib/ImageManager.php b/apps/theming/lib/ImageManager.php
index 761b0c9a8ba83..4afdedf51896b 100644
--- a/apps/theming/lib/ImageManager.php
+++ b/apps/theming/lib/ImageManager.php
@@ -194,6 +194,10 @@ public function delete(string $key): void {
} catch (NotFoundException $e) {
} catch (NotPermittedException $e) {
}
+
+ if ($key === 'logo') {
+ $this->config->deleteAppValue('theming', 'logoDimensions');
+ }
}
public function updateImage(string $key, string $tmpFile): string {
@@ -266,6 +270,25 @@ public function updateImage(string $key, string $tmpFile): string {
$target->putContent(file_get_contents($tmpFile));
+ if ($key === 'logo') {
+ $content = file_get_contents($tmpFile);
+ $newImage = @imagecreatefromstring($content);
+ if ($newImage !== false) {
+ $this->config->setAppValue('theming', 'logoDimensions', imagesx($newImage) . 'x' . imagesy($newImage));
+ } elseif (str_starts_with($detectedMimeType, 'image/svg')) {
+ $matched = preg_match('/viewbox=["\']\d* \d* (\d*\.?\d*) (\d*\.?\d*)["\']/i', $content, $matches);
+ if ($matched) {
+ $this->config->setAppValue('theming', 'logoDimensions', $matches[1] . 'x' . $matches[2]);
+ } else {
+ $this->logger->warning('Could not read logo image dimensions to optimize for mail header');
+ $this->config->deleteAppValue('theming', 'logoDimensions');
+ }
+ } else {
+ $this->logger->warning('Could not read logo image dimensions to optimize for mail header');
+ $this->config->deleteAppValue('theming', 'logoDimensions');
+ }
+ }
+
return $detectedMimeType;
}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 3f0ce230fec67..b0b60b3e0bbb7 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -1757,6 +1757,7 @@
'OC\\Repair\\RemoveLinkShares' => $baseDir . '/lib/private/Repair/RemoveLinkShares.php',
'OC\\Repair\\RepairDavShares' => $baseDir . '/lib/private/Repair/RepairDavShares.php',
'OC\\Repair\\RepairInvalidShares' => $baseDir . '/lib/private/Repair/RepairInvalidShares.php',
+ 'OC\\Repair\\RepairLogoDimension' => $baseDir . '/lib/private/Repair/RepairLogoDimension.php',
'OC\\Repair\\RepairMimeTypes' => $baseDir . '/lib/private/Repair/RepairMimeTypes.php',
'OC\\RichObjectStrings\\Validator' => $baseDir . '/lib/private/RichObjectStrings/Validator.php',
'OC\\Route\\CachingRouter' => $baseDir . '/lib/private/Route/CachingRouter.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index bc23e72ab3c23..648b736bb7784 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -1790,6 +1790,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Repair\\RemoveLinkShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveLinkShares.php',
'OC\\Repair\\RepairDavShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairDavShares.php',
'OC\\Repair\\RepairInvalidShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairInvalidShares.php',
+ 'OC\\Repair\\RepairLogoDimension' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairLogoDimension.php',
'OC\\Repair\\RepairMimeTypes' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairMimeTypes.php',
'OC\\RichObjectStrings\\Validator' => __DIR__ . '/../../..' . '/lib/private/RichObjectStrings/Validator.php',
'OC\\Route\\CachingRouter' => __DIR__ . '/../../..' . '/lib/private/Route/CachingRouter.php',
diff --git a/lib/private/Mail/EMailTemplate.php b/lib/private/Mail/EMailTemplate.php
index 80740e14acacc..cbb006203e138 100644
--- a/lib/private/Mail/EMailTemplate.php
+++ b/lib/private/Mail/EMailTemplate.php
@@ -76,7 +76,7 @@ class EMailTemplate implements IEMailTemplate {
-
+
@@ -308,6 +308,8 @@ public function __construct(
protected Defaults $themingDefaults,
protected IURLGenerator $urlGenerator,
protected IFactory $l10nFactory,
+ protected ?int $logoWidth,
+ protected ?int $logoHeight,
protected string $emailId,
protected array $data,
) {
@@ -330,8 +332,14 @@ public function addHeader(): void {
}
$this->headerAdded = true;
+ $logoSizeDimensions = '';
+ if ($this->logoWidth && $this->logoHeight) {
+ // Provide a logo size when we have the dimensions so that it displays nicely in Outlook
+ $logoSizeDimensions = ' width="' . $this->logoWidth . '" height="' . $this->logoHeight . '"';
+ }
+
$logoUrl = $this->urlGenerator->getAbsoluteURL($this->themingDefaults->getLogo(false));
- $this->htmlBody .= vsprintf($this->header, [$this->themingDefaults->getDefaultColorPrimary(), $logoUrl, $this->themingDefaults->getName()]);
+ $this->htmlBody .= vsprintf($this->header, [$this->themingDefaults->getDefaultColorPrimary(), $logoUrl, $this->themingDefaults->getName(), $logoSizeDimensions]);
}
/**
diff --git a/lib/private/Mail/Mailer.php b/lib/private/Mail/Mailer.php
index e866cbfdbbc34..4ddb748fc26d4 100644
--- a/lib/private/Mail/Mailer.php
+++ b/lib/private/Mail/Mailer.php
@@ -52,6 +52,12 @@
* @package OC\Mail
*/
class Mailer implements IMailer {
+ // Do not move this block or change it's content without contacting the release crew
+ public const DEFAULT_DIMENSIONS = '252x120';
+ // Do not move this block or change it's content without contacting the release crew
+
+ public const MAX_LOGO_SIZE = 105;
+
private ?MailerInterface $instance = null;
public function __construct(
@@ -109,10 +115,37 @@ public function createEMailTemplate(string $emailId, array $data = []): IEMailTe
);
}
+ $logoDimensions = $this->config->getAppValue('theming', 'logoDimensions', self::DEFAULT_DIMENSIONS);
+ if (str_contains($logoDimensions, 'x')) {
+ [$width, $height] = explode('x', $logoDimensions);
+ $width = (int) $width;
+ $height = (int) $height;
+
+ if ($width > self::MAX_LOGO_SIZE || $height > self::MAX_LOGO_SIZE) {
+ if ($width === $height) {
+ $logoWidth = self::MAX_LOGO_SIZE;
+ $logoHeight = self::MAX_LOGO_SIZE;
+ } elseif ($width > $height) {
+ $logoWidth = self::MAX_LOGO_SIZE;
+ $logoHeight = (int) (($height / $width) * self::MAX_LOGO_SIZE);
+ } else {
+ $logoWidth = (int) (($width / $height) * self::MAX_LOGO_SIZE);
+ $logoHeight = self::MAX_LOGO_SIZE;
+ }
+ } else {
+ $logoWidth = $width;
+ $logoHeight = $height;
+ }
+ } else {
+ $logoWidth = $logoHeight = null;
+ }
+
return new EMailTemplate(
$this->defaults,
$this->urlGenerator,
$this->l10nFactory,
+ $logoWidth,
+ $logoHeight,
$emailId,
$data
);
diff --git a/lib/private/Repair.php b/lib/private/Repair.php
index ed9cd400f617a..a41c6c5277e00 100644
--- a/lib/private/Repair.php
+++ b/lib/private/Repair.php
@@ -52,6 +52,7 @@
use OC\Repair\RemoveLinkShares;
use OC\Repair\RepairDavShares;
use OC\Repair\RepairInvalidShares;
+use OC\Repair\RepairLogoDimension;
use OC\Repair\RepairMimeTypes;
use OC\Template\JSCombiner;
use OCA\DAV\Migration\DeleteSchedulingObjects;
@@ -187,6 +188,7 @@ public static function getRepairSteps(): array {
\OCP\Server::get(AddRemoveOldTasksBackgroundJob::class),
\OCP\Server::get(AddMetadataGenerationJob::class),
\OCP\Server::get(AddAppConfigLazyMigration::class),
+ \OCP\Server::get(RepairLogoDimension::class),
];
}
diff --git a/lib/private/Repair/RepairLogoDimension.php b/lib/private/Repair/RepairLogoDimension.php
new file mode 100644
index 0000000000000..122da205986a0
--- /dev/null
+++ b/lib/private/Repair/RepairLogoDimension.php
@@ -0,0 +1,71 @@
+config->getAppValue('theming', 'logoDimensions');
+ if (preg_match('/^\d+x\d+$/', $logoDimensions)) {
+ $output->info('Logo dimensions are already known');
+ return;
+ }
+
+ try {
+ /** @var ImageManager $imageManager */
+ $imageManager = Server::get(ImageManager::class);
+ } catch (\Throwable) {
+ $output->info('Theming is disabled');
+ return;
+ }
+
+ if (!$imageManager->hasImage('logo')) {
+ $output->info('Theming is not used to provide a logo');
+ return;
+ }
+
+ $simpleFile = $imageManager->getImage('logo', false);
+
+ $image = @imagecreatefromstring($simpleFile->getContent());
+
+ $dimensions = '';
+ if ($image !== false) {
+ $dimensions = imagesx($image) . 'x' . imagesy($image);
+ } elseif (str_starts_with($simpleFile->getMimeType(), 'image/svg')) {
+ $matched = preg_match('/viewbox=["\']\d* \d* (\d*\.?\d*) (\d*\.?\d*)["\']/i', $simpleFile->getContent(), $matches);
+ if ($matched) {
+ $dimensions = $matches[1] . 'x' . $matches[2];
+ }
+ }
+
+ if (!$dimensions) {
+ $output->warning('Failed to read dimensions from logo');
+ $this->config->deleteAppValue('theming', 'logoDimensions');
+ return;
+ }
+
+ $dimensions = imagesx($image) . 'x' . imagesy($image);
+ $this->config->setAppValue('theming', 'logoDimensions', $dimensions);
+ $output->info('Updated logo dimensions: ' . $dimensions);
+ }
+}
diff --git a/tests/data/emails/new-account-email-custom.html b/tests/data/emails/new-account-email-custom.html
index e1c9fd4fb4f81..370a2f749d74e 100644
--- a/tests/data/emails/new-account-email-custom.html
+++ b/tests/data/emails/new-account-email-custom.html
@@ -23,7 +23,7 @@
-
+
diff --git a/tests/data/emails/new-account-email-single-button.html b/tests/data/emails/new-account-email-single-button.html
index 35ad9b14a1c0f..51ed5b16f66a6 100644
--- a/tests/data/emails/new-account-email-single-button.html
+++ b/tests/data/emails/new-account-email-single-button.html
@@ -23,7 +23,7 @@
-
+
diff --git a/tests/data/emails/new-account-email.html b/tests/data/emails/new-account-email.html
index e879f44120676..e45edba74eea0 100644
--- a/tests/data/emails/new-account-email.html
+++ b/tests/data/emails/new-account-email.html
@@ -23,7 +23,7 @@
-
+
diff --git a/tests/lib/Mail/EMailTemplateTest.php b/tests/lib/Mail/EMailTemplateTest.php
index a12cf82ab50e7..45ccf54384818 100644
--- a/tests/lib/Mail/EMailTemplateTest.php
+++ b/tests/lib/Mail/EMailTemplateTest.php
@@ -38,6 +38,8 @@ protected function setUp(): void {
$this->defaults,
$this->urlGenerator,
$this->l10n,
+ 252,
+ 120,
'test.TestTemplate',
[]
);
diff --git a/tests/lib/Mail/MailerTest.php b/tests/lib/Mail/MailerTest.php
index 91006a8331aba..be95307da6d2e 100644
--- a/tests/lib/Mail/MailerTest.php
+++ b/tests/lib/Mail/MailerTest.php
@@ -236,6 +236,9 @@ public function testCreateEMailTemplate() {
$this->config->method('getSystemValueString')
->with('mail_template_class', '')
->willReturnArgument(1);
+ $this->config->method('getAppValue')
+ ->with('theming', 'logoDimensions', Mailer::DEFAULT_DIMENSIONS)
+ ->willReturn(Mailer::DEFAULT_DIMENSIONS);
$this->assertSame(EMailTemplate::class, get_class($this->mailer->createEMailTemplate('tests.MailerTest')));
}