Files
SRCmail/lib/__tests__/forward-as-attachment.test.ts
T
Aaron Guise edd11ac27b fix: strip from/to names from forward-as-attachment filenames
buildForwardAsAttachmentPayload named the synthetic .eml attachment
using the user's own emailDownloadTemplate, which by default embeds
sender/recipient display names. Since this attachment can go to an
external recipient (e.g. an upstream spam gateway, or anyone else),
the filename now always renders as "{date}-{subject}.eml" regardless
of the user's configured template, while still honoring their
space/case/diacritics preferences.
2026-07-29 11:41:34 +12:00

85 lines
3.3 KiB
TypeScript

// Pin TZ so the local-time date rendering in the filename test is deterministic.
process.env.TZ = 'UTC';
import { describe, it, expect } from 'vitest';
import { buildForwardAsAttachmentPayload } from '@/lib/forward-as-attachment';
import type { Email } from '@/lib/jmap/types';
function makeEmail(overrides: Partial<Email> = {}): Email {
return {
id: 'e1',
threadId: 't1',
mailboxIds: { inbox: true },
keywords: {},
size: 12345,
receivedAt: '2026-07-26T22:25:22Z',
subject: 'Your waste service day is changing',
hasAttachment: false,
blobId: 'blob123',
...overrides,
};
}
describe('buildForwardAsAttachmentPayload', () => {
it('returns null when the email has no blobId', () => {
const email = makeEmail({ blobId: undefined });
expect(buildForwardAsAttachmentPayload(email, 'Fwd:')).toBeNull();
});
it('prefixes the subject using the given forward prefix', () => {
const email = makeEmail({ subject: 'Missed spam example' });
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:');
expect(payload?.subject).toBe('Fwd: Missed spam example');
});
it('builds a message/rfc822 attachment referencing the email\'s own blobId, not a new upload', () => {
const email = makeEmail({ blobId: 'the-real-blob-id', size: 26489 });
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:');
expect(payload?.attachment).toEqual({
blobId: 'the-real-blob-id',
name: expect.stringMatching(/\.eml$/),
type: 'message/rfc822',
size: 26489,
});
});
it('is idempotent - repeated forwarding does not stack prefixes', () => {
const email = makeEmail({ subject: 'Fwd: already forwarded once' });
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:');
expect(payload?.subject).toBe('Fwd: already forwarded once');
});
it('leaves the subject blank (not just the bare prefix) for a subject-less message, matching normal Forward', () => {
const email = makeEmail({ subject: undefined });
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:');
expect(payload?.subject).toBe('');
});
it('applies user space/case transforms but ignores a custom filename template, unlike "Export as .eml"', () => {
const email = makeEmail({ subject: 'Missed spam example' });
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:', {
template: 'custom-{subject}',
lowercase: true,
spaceReplacement: 'dash',
});
expect(payload?.attachment.name).toBe('2026-07-26-22.25.22-missed-spam-example.eml');
});
it('uses a dash between date and subject by default', () => {
const email = makeEmail({ subject: 'Missed spam example' });
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:');
expect(payload?.attachment.name).toBe('2026-07-26 22.25.22-Missed spam example.eml');
});
it('never includes from/to in the filename, even with the default template, to avoid leaking names to the recipient', () => {
const email = makeEmail({
subject: 'Missed spam example',
from: [{ name: 'Alice Sender', email: 'alice@example.com' }],
to: [{ name: "'Bobby'", email: 'bob@example.com' }],
});
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:');
expect(payload?.attachment.name).not.toContain('Alice');
expect(payload?.attachment.name).not.toContain('Bobby');
});
});