diff --git a/src/components/MenuEnvelope.vue b/src/components/MenuEnvelope.vue
index 0f1fe735ce..09dcc65182 100644
--- a/src/components/MenuEnvelope.vue
+++ b/src/components/MenuEnvelope.vue
@@ -1,5 +1,5 @@
@@ -178,6 +178,20 @@
{{ t('mail', 'Print message') }}
+
+
+
+
+
+ {{ copied ? t('mail', 'Link copied') : t('mail', 'Copy direct link for other user. This only works if they have received the same email.') }}
+
@@ -277,6 +291,7 @@ import CalendarClock from 'vue-material-design-icons/CalendarClockOutline.vue'
import CheckIcon from 'vue-material-design-icons/Check.vue'
import TaskIcon from 'vue-material-design-icons/CheckboxMarkedCirclePlusOutline.vue'
import ChevronLeft from 'vue-material-design-icons/ChevronLeft.vue'
+import ContentCopyIcon from 'vue-material-design-icons/ContentCopy.vue'
import DotsHorizontalIcon from 'vue-material-design-icons/DotsHorizontal.vue'
import FilterIcon from 'vue-material-design-icons/FilterOutline.vue'
import InformationIcon from 'vue-material-design-icons/InformationOutline.vue'
@@ -321,6 +336,7 @@ export default {
AlarmIcon,
PrinterIcon,
FilterIcon,
+ ContentCopyIcon,
},
props: {
@@ -367,6 +383,8 @@ export default {
snoozeActionsOpen: false,
forwardMessages: this.envelope.databaseId,
customSnoozeDateTime: new Date(moment().add(2, 'hours').minute(0).second(0).valueOf()),
+ copied: false,
+ copyResetTimer: null,
}
},
@@ -634,6 +652,35 @@ export default {
this.$emit('print')
},
+ async onCopyMessageLink() {
+ if (this.copyResetTimer) {
+ clearTimeout(this.copyResetTimer)
+ }
+
+ if (!this.envelope || typeof this.envelope.messageId !== 'string' || !this.envelope.messageId.trim()) {
+ showError(t('mail', 'Could not generate direct link: Message ID is missing'))
+ return
+ }
+
+ const trimmedMessageId = this.envelope.messageId.trim().replace(/^<|>$/g, '')
+ const url = window.location.origin + generateUrl('/apps/mail/open/' + encodeURIComponent(trimmedMessageId))
+
+ try {
+ await navigator.clipboard.writeText(url)
+ this.copied = true
+ showSuccess(t('mail', 'Direct link copied to clipboard'))
+ } catch (error) {
+ // Fallback for cases where clipboard API is not available (e.g. non-HTTPS localhost)
+ // or permission is denied. This exactly matches Nextcloud's useCopy composable behavior.
+ window.prompt(t('mail', 'Copy direct link for other user. This only works if they have received the same email.'), url)
+ } finally {
+ this.copyResetTimer = setTimeout(() => {
+ this.copied = false
+ this.localMoreActionsOpen = false
+ }, 2000)
+ }
+ },
+
isSieveEnabled() {
return this.account.sieveEnabled
},