import {config} from 'dotenv'; import {ImapFlow} from 'imapflow'; import express from 'express'; config({path: '.env.local'}); const app = express(); const port = process.env.PORT || 4000; app.use(async (request, response, next) => { try { const [user, pass] = Buffer.from(request.headers['authorization']!.replace(/^Basic /, ''), 'base64') .toString('utf8') .split(':'); const client = new ImapFlow({ host: 'imap.server.uni-frankfurt.de', port: 993, secure: true, emitLogs: false, auth: {user, pass}, }); response.locals.client = client; await client.connect(); response.on('finish', async () => { await client.logout(); client.close(); }); next(); } catch { response.status(401).send(); } }); app.get('/', async (_request, response) => { const result = await response.locals.client.listTree(); response.json(result); }); app.get('/:mailbox', async (request, response) => { try { await response.locals.client.mailboxOpen(request.params.mailbox); const since = Number(request.query.since) || undefined; const preData = await response.locals.client.status(request.params.mailbox, {messages: true}); if (preData.messages === 0) { response.json([]); return; } const data = response.locals.client.fetch( '1:*', {}, { // caution, BigInt can throw changedSince: typeof since === 'string' ? BigInt(since) : undefined, }, ); const messages = []; for await (const message of data) { messages.push(message.seq.toString()); } response.json(messages); } catch (error) { console.error(error); response.status(404).send(); } }); app.get('/:mailbox/:id', async (request, response) => { try { await response.locals.client.mailboxOpen(request.params.mailbox); const message = await response.locals.client.fetchOne(request.params.id, { envelope: true, labels: true, flags: true, bodyStructure: true, }); response.json({ bodyStructure: message.bodyStructure, labels: [...(message.labels ?? [])], flags: [...(message.flags ?? [])], envelope: message.envelope, seq: message.seq, }); } catch (error) { console.error(error); response.status(404).send(); } }); app.get('/:mailbox/:id/:part', async (request, response) => { try { await response.locals.client.mailboxOpen(request.params.mailbox, {readOnly: true}); if (request.query.raw) { const message = await response.locals.client.fetchOne(request.params.id, { bodyParts: [`${request.params.part}.mime`, request.params.part], }); response.write(message.bodyParts.get(`${request.params.part}.mime`)); response.write(message.bodyParts.get(request.params.part)); response.end(); } else { const message = await response.locals.client.download(request.params.id, request.params.part); message.content.on('data', chunk => { response.write(chunk); }); message.content.on('end', () => { response.end(); }); } } catch (error) { console.error(error); response.status(404).send(); } }); app.listen(port, () => { console.log(`Server listening on port ${port}`); });