diff options
author | Yuqian Yang <crupest@crupest.life> | 2025-06-30 14:25:02 +0800 |
---|---|---|
committer | Yuqian Yang <crupest@crupest.life> | 2025-06-30 14:25:02 +0800 |
commit | 5f00fdd06fa51bb0c82928e060d3f8811bc171e9 (patch) | |
tree | 4aaf446eeb120ccf62bbbd2696d576a3235c7f4f /deno/mail/app.ts | |
parent | 7178983a5b8a27d5f0f5b447528f0e23b50d75c1 (diff) | |
download | crupest-5f00fdd06fa51bb0c82928e060d3f8811bc171e9.tar.gz crupest-5f00fdd06fa51bb0c82928e060d3f8811bc171e9.tar.bz2 crupest-5f00fdd06fa51bb0c82928e060d3f8811bc171e9.zip |
mail: revert removing.
Diffstat (limited to 'deno/mail/app.ts')
-rw-r--r-- | deno/mail/app.ts | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/deno/mail/app.ts b/deno/mail/app.ts new file mode 100644 index 0000000..332c430 --- /dev/null +++ b/deno/mail/app.ts @@ -0,0 +1,83 @@ +import { Hono } from "hono"; +import { logger as honoLogger } from "hono/logger"; + +import { + AliasRecipientMailHook, + FallbackRecipientHook, + MailDeliverer, + RecipientFromHeadersHook, +} from "./mail.ts"; +import { DovecotMailDeliverer } from "./dovecot.ts"; +import { DumbSmtpServer } from "./dumb-smtp-server.ts"; + +export function createInbound( + { + fallback, + mailDomain, + aliasFile, + ldaPath, + doveadmPath, + }: { + fallback: string[]; + mailDomain: string; + aliasFile: string; + ldaPath: string; + doveadmPath: string; + }, +) { + const deliverer = new DovecotMailDeliverer(ldaPath, doveadmPath); + deliverer.preHooks.push( + new RecipientFromHeadersHook(mailDomain), + new FallbackRecipientHook(new Set(fallback)), + new AliasRecipientMailHook(aliasFile), + ); + return deliverer; +} + +export function createHono(outbound: MailDeliverer, inbound: MailDeliverer) { + const hono = new Hono(); + + hono.onError((err, c) => { + console.error("Hono handler threw an uncaught error.", err); + return c.json({ message: "Server error, check its log." }, 500); + }); + hono.use(honoLogger()); + hono.post("/send/raw", async (context) => { + const body = await context.req.text(); + if (body.trim().length === 0) { + return context.json({ message: "Can't send an empty mail." }, 400); + } else { + const result = await outbound.deliverRaw(body); + return context.json({ + awsMessageId: result.awsMessageId, + }); + } + }); + hono.post("/receive/raw", async (context) => { + await inbound.deliverRaw(await context.req.text()); + return context.json({ message: "Done!" }); + }); + + return hono; +} + +export function createSmtp(outbound: MailDeliverer) { + return new DumbSmtpServer(outbound); +} + +export async function sendMail(port: number) { + const decoder = new TextDecoder(); + let text = ""; + for await (const chunk of Deno.stdin.readable) { + text += decoder.decode(chunk); + } + + const res = await fetch(`http://127.0.0.1:${port}/send/raw`, { + method: "post", + body: text, + }); + const fn = res.ok ? "info" : "error"; + console[fn](res); + console[fn](await res.text()); + if (!res.ok) Deno.exit(-1); +} |