diff --git a/.changeset/fn-7864-artifact-mail-link.md b/.changeset/fn-7864-artifact-mail-link.md
new file mode 100644
index 0000000000..9131380d5b
--- /dev/null
+++ b/.changeset/fn-7864-artifact-mail-link.md
@@ -0,0 +1,7 @@
+---
+"@runfusion/fusion": minor
+---
+
+summary: Artifact-registration mail notifications now show an inline preview and open link.
+category: feature
+dev: MailboxView/MailboxModal render a shared MailboxArtifactAttachment from message.metadata (artifactId/artifactType/mimeType) via artifactMediaUrl; notifyArtifactRegistered now also emits metadata.mimeType.
diff --git a/docs/dashboard-guide.md b/docs/dashboard-guide.md
index 86d9112832..8e9c514cc7 100644
--- a/docs/dashboard-guide.md
+++ b/docs/dashboard-guide.md
@@ -613,7 +613,7 @@ Mailbox view shows inbox/outbox communication threads and unread state.
- Inbox renders one row per message (no sender-based collapsing)
- clicking a message in the Mail tab opens the task detail pane with full message content and conversation context
- reply rows in the mailbox modal can expand inline to show the replied-to message context for easier thread reading
-- when an agent or dashboard chat session registers an artifact with `fn_artifact_register`, Fusion sends a best-effort `system` → user inbox message announcing the new artifact (for example, `New image artifact registered:
`) with metadata for `artifactId`, `artifactType`, `title`, `authorId`, and optional `taskId`; notification delivery is informational and never blocks or rolls back the artifact registration
+- when an agent or dashboard chat session registers an artifact with `fn_artifact_register`, Fusion sends a best-effort `system` → user inbox message announcing the new artifact (for example, `New image artifact registered: `) with metadata for `artifactId`, `artifactType`, `title`, optional `mimeType`, `authorId`, and optional `taskId`; notification delivery is informational and never blocks or rolls back the artifact registration. Artifact notifications are actionable in message detail views: image artifacts show an inline preview plus **Open artifact**, while video/audio/document/other artifacts show an **Open artifact** link to the managed media URL.
- mailbox now includes an **Approvals** tab with pending and history filters (`approved` / `denied` / `completed`), approval detail context, and inline approve/deny actions for pending requests
- for approvals gated by an agent's permission policy (permanent agents and task-worker heartbeats), the Approvals detail pane renders the gated action's real payload — tool name, shell command line or structured arguments, and working directory when present — instead of only a generic "Agent gated action for ``" summary; a stateless heartbeat retrying the same gated command reuses the existing pending approval instead of creating a duplicate (FN-7609)
- in the **Agents** tab, the agent selector now includes **All agents**, which shows one combined agent-to-agent stream (with sender + recipient labels); selecting a specific agent still shows Inbox/Outbox subtabs
diff --git a/packages/dashboard/app/components/MailboxArtifactAttachment.tsx b/packages/dashboard/app/components/MailboxArtifactAttachment.tsx
new file mode 100644
index 0000000000..4cd6e6443b
--- /dev/null
+++ b/packages/dashboard/app/components/MailboxArtifactAttachment.tsx
@@ -0,0 +1,103 @@
+import { memo, useMemo, useState, type ReactNode } from "react";
+import type { ArtifactType } from "@fusion/core";
+import { artifactMediaUrl } from "../api";
+
+export interface MailboxArtifactAttachmentProps {
+ artifactId?: unknown;
+ artifactType?: unknown;
+ title?: unknown;
+ mimeType?: unknown;
+ projectId?: string;
+}
+
+function readString(value: unknown): string | undefined {
+ return typeof value === "string" && value.trim().length > 0 ? value : undefined;
+}
+
+function readArtifactType(value: unknown): ArtifactType | "unknown" {
+ return value === "image" || value === "video" || value === "audio" || value === "document" || value === "other"
+ ? value
+ : "unknown";
+}
+
+/**
+ * FNXC:ArtifactRegistry 2026-07-12-00:00:
+ * Artifact-registration mail messages must expose the artifact announced by message.metadata. Render image artifacts inline, keep every type reachable through artifactMediaUrl(projectId-aware), and render nothing when metadata has no artifactId so ordinary messages keep their exact layout.
+ */
+export const MailboxArtifactAttachment = memo(function MailboxArtifactAttachment({
+ artifactId,
+ artifactType,
+ title,
+ mimeType,
+ projectId,
+}: MailboxArtifactAttachmentProps) {
+ const id = readString(artifactId);
+ const type = readArtifactType(artifactType);
+ const label = readString(title) ?? "artifact";
+ const mediaMimeType = readString(mimeType);
+ const [imageFailed, setImageFailed] = useState(false);
+ const mediaUrl = useMemo(() => id ? artifactMediaUrl(id, projectId) : "", [id, projectId]);
+
+ if (!id) return null;
+
+ const openLink = (
+
+ Open artifact
+
+ );
+
+ let preview: ReactNode = null;
+ if (type === "image" && !imageFailed) {
+ preview = (
+ setImageFailed(true)}
+ />
+ );
+ } else if (type === "video") {
+ preview = (
+
+ );
+ } else if (type === "audio") {
+ preview = (
+
+ );
+ }
+
+ return (
+