Files
SRCmail/lib/forward-as-attachment.ts
T
Aaron Guise 3ea22161d9 feat: add "Forward as attachment" next to Export as .eml
Adds a "Forward as attachment" action to the message overflow menu
(desktop and mobile), right beside the existing "Export as .eml"
action. Opens a new forward-mode compose window with the original
message attached as a message/rfc822 file instead of quoted inline -
useful for reporting spam/phishing to an upstream gateway that expects
the raw original as an attachment (the primary motivating use case:
gateways like MxGuarddog require complete original headers, including
the full mail path, for scanning), or for preserving a message's exact
formatting/headers when forwarding.

Implementation reuses the composer's existing attachment-carry-forward
mechanism (the `attachments` useState initializer in
email-composer.tsx already carries a forwarded message's own
attachments into the new compose via `replyTo.attachments`) - this
just adds one synthetic entry representing the whole original message,
referenced by its existing blobId. No re-fetch or re-upload needed,
since JMAP blobs are account-scoped rather than per-email. The inline
quote-header step (prepareComposerQuoteHeader) is skipped, so the body
starts blank instead of quoting the original.

The core "build subject + attachment entry" logic is extracted into a
pure, unit-tested helper (lib/forward-as-attachment.ts) rather than
left inline in the already-large page component.

Adds the forward_as_attachment locale key to all 24 locales (English
text as a placeholder pending translation, following the existing
add-a-key convention) to satisfy the translations completeness test.
2026-07-27 15:31:52 +12:00

45 lines
1.3 KiB
TypeScript

import type { Email } from "@/lib/jmap/types";
import { buildForwardSubject } from "@/lib/subject-prefix";
import { emailExportFilename } from "@/lib/download-filename";
export interface ForwardAsAttachmentEntry {
blobId: string;
name: string;
type: "message/rfc822";
size: number;
}
export interface ForwardAsAttachmentPayload {
subject: string;
attachment: ForwardAsAttachmentEntry;
}
/**
* Build the subject and synthetic attachment entry for forwarding a
* message as a message/rfc822 attachment instead of inline-quoted text
* (e.g. reporting spam to an upstream gateway that expects the raw
* original as an attachment, or preserving exact formatting/headers).
*
* Referenced by blobId, not re-uploaded - JMAP blobs are account-scoped,
* not per-email, so the same blobId a message already has can be attached
* to a brand new outgoing email directly.
*
* Returns null when the email has no blobId (nothing to reference).
*/
export function buildForwardAsAttachmentPayload(
email: Email,
forwardPrefix: string,
): ForwardAsAttachmentPayload | null {
if (!email.blobId) return null;
return {
subject: buildForwardSubject(email.subject, forwardPrefix),
attachment: {
blobId: email.blobId,
name: emailExportFilename(email),
type: "message/rfc822",
size: email.size,
},
};
}