import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as fs from 'node:fs'; import * as os from 'node:os'; import * as path from 'node:path'; import { Email } from '../ts/mail/core/classes.email.js'; import { DKIMCreator } from '../ts/mail/security/classes.dkimcreator.js'; import { UnifiedEmailServer } from '../ts/mail/routing/classes.unified.email.server.js'; const storageMap = new Map(); const serversToCleanup: UnifiedEmailServer[] = []; const mockDcRouter = { storageManager: { get: async (key: string) => storageMap.get(key) || null, set: async (key: string, value: string) => { storageMap.set(key, value); }, list: async (prefix: string) => Array.from(storageMap.keys()).filter((key) => key.startsWith(prefix)), delete: async (key: string) => { storageMap.delete(key); }, }, }; tap.test('UnifiedEmailServer.sendEmail returns the actual queue item id', async () => { const server = new UnifiedEmailServer(mockDcRouter, { ports: [10025], hostname: 'mail.example.com', domains: [{ domain: 'example.com', dnsMode: 'forward' }], routes: [], }); serversToCleanup.push(server); const route = { name: 'test-deliver-route', match: { recipients: '*@*' }, action: { type: 'deliver' as const }, }; const email = new Email({ from: 'sender@example.com', to: ['recipient@example.net'], subject: 'Queue ID contract', text: 'hello', }); const queueId = await server.sendEmail(email, 'mta', route); const queuedItem = server.getQueueItem(queueId); expect(queuedItem).toBeTruthy(); expect(queuedItem?.id).toEqual(queueId); expect(server.getQueueStats().queueSize).toEqual(1); expect(server.getQueueItems().map((item) => item.id)).toContain(queueId); }); tap.test('UnifiedEmailServer.sendOutboundEmail uses outbound.hostname when configured', async () => { const server = new UnifiedEmailServer(mockDcRouter, { ports: [10026], hostname: 'mail.example.com', outbound: { hostname: 'outbound.example.com', }, domains: [{ domain: 'example.com', dnsMode: 'forward' }], routes: [], }); serversToCleanup.push(server); const email = new Email({ from: 'sender@example.com', to: ['recipient@example.net'], subject: 'Outbound hostname contract', text: 'hello', }); let capturedOptions: any; (server as any).rustBridge.sendOutboundEmail = async (options: any) => { capturedOptions = options; return { accepted: ['recipient@example.net'], rejected: [], messageId: 'test-message-id', response: '250 2.0.0 queued', envelope: { from: 'sender@example.com', to: ['recipient@example.net'], }, }; }; await server.sendOutboundEmail('smtp.target.example', 25, email); expect(capturedOptions).toBeTruthy(); expect(capturedOptions.domain).toEqual('outbound.example.com'); }); tap.test('DKIMCreator returns selector-aligned DNS record names', async () => { const tempDir = path.join(os.tmpdir(), `smartmta-dkim-${Date.now()}`); fs.mkdirSync(tempDir, { recursive: true }); try { const creator = new DKIMCreator(tempDir); await creator.createAndStoreDKIMKeys('example.com'); const defaultRecord = await creator.getDNSRecordForDomain('example.com'); expect(defaultRecord.name).toEqual('default._domainkey.example.com'); await creator.createAndStoreDKIMKeysForSelector('example.org', 'selector1'); const selectorRecord = await creator.getDNSRecordForDomain('example.org', 'selector1'); expect(selectorRecord.name).toEqual('selector1._domainkey.example.org'); } finally { fs.rmSync(tempDir, { recursive: true, force: true }); } }); tap.test('cleanup', async () => { for (const server of serversToCleanup) { await server.stop(); } await tap.stopForcefully(); }); export default tap.start();