Skip to content

feat: Add route to open messages via Message-ID#12632

Open
SoleroTG wants to merge 5 commits intonextcloud:mainfrom
SoleroTG:feature/message-id-deeplink
Open

feat: Add route to open messages via Message-ID#12632
SoleroTG wants to merge 5 commits intonextcloud:mainfrom
SoleroTG:feature/message-id-deeplink

Conversation

@SoleroTG
Copy link
Copy Markdown

Related to #2269

Hi @ChristophWurst, this is the first part of the deep-linking feature.

What this PR does

This PR introduces a new frontend route /apps/mail/open/<message-id> that allows opening a specific email directly if the Message-ID is known.

The app will search for a message with the given ID across all accounts and mailboxes of the user and open it if found.

This is the foundational work for a future UI element that will allow users to copy such a link. The button for generating the link is not part of this PR and will follow in a separate one.

How to test

  1. Find a Message-ID of an existing email (e.g., from the email source).
  2. Manually construct a URL like http://<your-nextcloud-instance>/index.php/apps/mail/open/<your-message-id>.
  3. Make sure to URL-encode the Message-ID (e.g., < becomes %3C).
  4. Navigate to the URL.
  5. The Mail app should open and display the corresponding email directly.

Comment thread lib/Controller/DeepLinkController.php Outdated
declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors

Comment thread lib/Controller/DeepLinkController.php Outdated
Comment on lines +33 to +38
MailAccountMapper $mailAccountMapper,
AccountService $accountService,
MessageMapper $messageMapper,
IURLGenerator $urlGenerator,
IUserSession $userSession,
LoggerInterface $logger
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
MailAccountMapper $mailAccountMapper,
AccountService $accountService,
MessageMapper $messageMapper,
IURLGenerator $urlGenerator,
IUserSession $userSession,
LoggerInterface $logger
private MailAccountMapper $mailAccountMapper,
private AccountService $accountService,
private MessageMapper $messageMapper,
private IURLGenerator $urlGenerator,
private IUserSession $userSession,
private LoggerInterface $logger

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Adding private/protected/public in a class constructor = shortcut to create a property with the given name and assign the value to it.

Comment thread lib/Controller/DeepLinkController.php Outdated
Comment on lines +23 to +28
private MailAccountMapper $mailAccountMapper;
private AccountService $accountService;
private MessageMapper $messageMapper;
private IURLGenerator $urlGenerator;
private IUserSession $userSession;
private LoggerInterface $logger;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
private MailAccountMapper $mailAccountMapper;
private AccountService $accountService;
private MessageMapper $messageMapper;
private IURLGenerator $urlGenerator;
private IUserSession $userSession;
private LoggerInterface $logger;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment thread lib/Controller/DeepLinkController.php Outdated
Comment on lines +41 to +46
$this->mailAccountMapper = $mailAccountMapper;
$this->accountService = $accountService;
$this->messageMapper = $messageMapper;
$this->urlGenerator = $urlGenerator;
$this->userSession = $userSession;
$this->logger = $logger;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
$this->mailAccountMapper = $mailAccountMapper;
$this->accountService = $accountService;
$this->messageMapper = $messageMapper;
$this->urlGenerator = $urlGenerator;
$this->userSession = $userSession;
$this->logger = $logger;

Comment thread lib/Controller/DeepLinkController.php Outdated
/**
* @NoAdminRequired
* @NoCSRFRequired
* @PublicPage
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @PublicPage

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not a public page

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Still valid

Comment thread lib/Controller/DeepLinkController.php Outdated

/**
* @NoAdminRequired
* @NoCSRFRequired
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @NoCSRFRequired

@kesselb
Copy link
Copy Markdown
Contributor

kesselb commented Mar 30, 2026

Thanks a lot for your pr, I will give it a test this week.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 4, 2026

Hello there,
Thank you so much for taking the time and effort to create a pull request to our Nextcloud project.

We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process.

Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6

Thank you for contributing to Nextcloud and we hope to hear from you soon!

(If you believe you should not receive this message, you can add yourself to the blocklist.)

@kesselb
Copy link
Copy Markdown
Contributor

kesselb commented Apr 16, 2026

Thanks again @SoleroTG for your pr.

Please apply the suggested changes.

The linter is failing, could you please format the code accordingly (composer run cs:fix).

@SoleroTG SoleroTG force-pushed the feature/message-id-deeplink branch from a38f75a to 016633b Compare April 16, 2026 23:14
Signed-off-by: SoleroTG <github-29h@solero.quietmail.eu>
Signed-off-by: SoleroTG <github-29h@solero.quietmail.eu>
Signed-off-by: SoleroTG <github-29h@solero.quietmail.eu>
This adds tests to verify the deep link routing behavior for message-id searches. It uses real instantiations of MailAccount and Message entities instead of mocks to properly test magic methods like getId() and getMailboxId() that cannot be configured on mocks.

AI-assisted: Gemini CLI (Gemini 2.5 Pro)

Signed-off-by: SoleroTG <github-29h@solero.quietmail.eu>
@SoleroTG SoleroTG force-pushed the feature/message-id-deeplink branch from d3e675a to 4ce7b44 Compare April 18, 2026 08:38
@SoleroTG
Copy link
Copy Markdown
Author

Thanks @kesselb for your feedback.

I have applied the formatting, added the requested unit tests for the DeepLinkController and fixed the DCO issue. The PR is ready for another review!

Comment thread lib/Controller/DeepLinkController.php Outdated
Comment on lines +23 to +28
private MailAccountMapper $mailAccountMapper;
private AccountService $accountService;
private MessageMapper $messageMapper;
private IURLGenerator $urlGenerator;
private IUserSession $userSession;
private LoggerInterface $logger;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Comment thread lib/Controller/DeepLinkController.php Outdated
/**
* @NoAdminRequired
* @NoCSRFRequired
* @PublicPage
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Still valid

Comment thread lib/Controller/DeepLinkController.php Outdated
Comment on lines +66 to +67
// Ensure formatting: Always wrapped in <>
$cleanedId = '<' . trim($messageId, '<>') . '>';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use Horde_Mail_Rfc822_Identification like we do at \OCA\Mail\Db\Message::parseMessageId.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Thanks @ChristophWurst for your feedback.

I applied the changes. Please let me know If I forgot anything.

Signed-off-by: SoleroTG <github-29h@solero.quietmail.eu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants