From 7db93b1ae4b716921e6ceba99c33168a2a29640e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Wed, 29 Jul 2026 12:14:54 +0200 Subject: [PATCH] feat(web): make local email capture browser-open configurable via LOCAL_EMAIL_OPEN_BROWSER Locally captured emails (dev outbox) always opened in a browser tab. Set LOCAL_EMAIL_OPEN_BROWSER=false to keep the capture on disk under dev/logs/emails/ without popping a tab. Defaults to current behavior. --- ENVIRONMENT.md | 1 + apps/web/src/lib/email-local-outbox.test.ts | 23 +++++++++++++++++++++ apps/web/src/lib/email-local-outbox.ts | 4 +++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/ENVIRONMENT.md b/ENVIRONMENT.md index c0b5b98a1b..e5d020bce7 100644 --- a/ENVIRONMENT.md +++ b/ENVIRONMENT.md @@ -246,6 +246,7 @@ Manage shared web env var additions and rotations with `pnpm web:env set ({ execFile: jest.fn() })); const execFileMock = jest.mocked(execFile); let temporaryDirectory: string; +const originalOpenBrowser = process.env.LOCAL_EMAIL_OPEN_BROWSER; beforeEach(async () => { temporaryDirectory = await mkdtemp(path.join(tmpdir(), 'kilo-email-outbox-')); + delete process.env.LOCAL_EMAIL_OPEN_BROWSER; }); afterEach(async () => { execFileMock.mockReset(); + if (originalOpenBrowser === undefined) { + delete process.env.LOCAL_EMAIL_OPEN_BROWSER; + } else { + process.env.LOCAL_EMAIL_OPEN_BROWSER = originalOpenBrowser; + } await rm(temporaryDirectory, { recursive: true, force: true }); }); @@ -74,6 +81,22 @@ describe('local email outbox', () => { ).resolves.toEqual(expect.stringMatching(/\.html$/)); }); + it('does not open the captured email when LOCAL_EMAIL_OPEN_BROWSER is false', async () => { + process.env.LOCAL_EMAIL_OPEN_BROWSER = 'false'; + + const filePath = await writeEmailToLocalOutbox( + { + to: 'developer@example.com', + subject: 'Local test', + html: '

Body

', + }, + temporaryDirectory + ); + + expect(filePath).toMatch(/\.html$/); + expect(execFileMock).not.toHaveBeenCalled(); + }); + it('escapes metadata before adding it to the captured HTML', async () => { const filePath = await writeEmailToLocalOutbox( { diff --git a/apps/web/src/lib/email-local-outbox.ts b/apps/web/src/lib/email-local-outbox.ts index 7d46164085..dcea0dc176 100644 --- a/apps/web/src/lib/email-local-outbox.ts +++ b/apps/web/src/lib/email-local-outbox.ts @@ -77,6 +77,8 @@ export async function writeEmailToLocalOutbox( const filePath = path.join(directory, `${timestamp}-${randomUUID()}.html`); const html = addDevelopmentBanner(params.html, developmentBanner(params)); await writeFile(filePath, html, { encoding: 'utf8', flag: 'wx', mode: 0o600 }); - openEmail(filePath); + if (process.env.LOCAL_EMAIL_OPEN_BROWSER !== 'false') { + openEmail(filePath); + } return filePath; }