aboutsummaryrefslogtreecommitdiff
path: root/deno/mail-relay/dumb-smtp-server.ts
diff options
context:
space:
mode:
Diffstat (limited to 'deno/mail-relay/dumb-smtp-server.ts')
-rw-r--r--deno/mail-relay/dumb-smtp-server.ts85
1 files changed, 47 insertions, 38 deletions
diff --git a/deno/mail-relay/dumb-smtp-server.ts b/deno/mail-relay/dumb-smtp-server.ts
index 6c63f5c..66c2f7c 100644
--- a/deno/mail-relay/dumb-smtp-server.ts
+++ b/deno/mail-relay/dumb-smtp-server.ts
@@ -1,32 +1,39 @@
-import config from "./config.ts";
-import log from "./log.ts";
+import { Logger } from "@crupest/base/log";
import { MailDeliverer } from "./mail.ts";
const CRLF = "\r\n";
-const SERVER_NAME = `[${config.SMTP_HOST}]:${config.SMTP_PORT}`;
-
-const RESPONSES = {
- "READY": `220 ${SERVER_NAME} SMTP Ready`,
- "EHLO": `250 ${SERVER_NAME}`,
- "MAIL": "250 2.1.0 Sender OK",
- "RCPT": "250 2.1.5 Recipient OK",
- "DATA": "354 Start mail input; end with <CRLF>.<CRLF>",
- "QUIT": `211 2.0.0 ${SERVER_NAME} closing connection`,
- "INVALID": "500 5.5.1 Error: command not recognized",
-} as const;
+function createResponses(host: string, port: number | string) {
+ const serverName = `[${host}]:${port}`;
+ return {
+ serverName,
+ READY: `220 ${serverName} SMTP Ready`,
+ EHLO: `250 ${serverName}`,
+ MAIL: "250 2.1.0 Sender OK",
+ RCPT: "250 2.1.5 Recipient OK",
+ DATA: "354 Start mail input; end with <CRLF>.<CRLF>",
+ QUIT: `211 2.0.0 ${serverName} closing connection`,
+ INVALID: "500 5.5.1 Error: command not recognized",
+ } as const;
+}
export class DumbSmtpServer {
- #deliverer: MailDeliverer;
-
- constructor(deliverer: MailDeliverer) {
+ #logger;
+ #deliverer;
+ #responses: ReturnType<typeof createResponses> = createResponses(
+ "invalid",
+ "invalid",
+ );
+
+ constructor(logger: Logger, deliverer: MailDeliverer) {
+ this.#logger = logger;
this.#deliverer = deliverer;
}
async #handleConnection(conn: Deno.Conn) {
using disposeStack = new DisposableStack();
disposeStack.defer(() => {
- log.info("Close smtp session tcp connection.");
+ this.#logger.info("Close smtp session tcp connection.");
conn.close();
});
const writer = conn.writable.getWriter();
@@ -42,7 +49,7 @@ export class DumbSmtpServer {
let buffer: string = "";
let rawMail: string | null = null;
- await send(RESPONSES["READY"]);
+ await send(this.#responses["READY"]);
while (true) {
const { value, done } = await reader.read();
@@ -58,36 +65,36 @@ export class DumbSmtpServer {
buffer = buffer.slice(eolPos + CRLF.length);
if (rawMail == null) {
- log.info("Smtp server received line:", line);
+ this.#logger.info("Smtp server received line:", line);
const upperLine = line.toUpperCase();
if (upperLine.startsWith("EHLO") || upperLine.startsWith("HELO")) {
- await send(RESPONSES["EHLO"]);
+ await send(this.#responses["EHLO"]);
} else if (upperLine.startsWith("MAIL FROM:")) {
- await send(RESPONSES["MAIL"]);
+ await send(this.#responses["MAIL"]);
} else if (upperLine.startsWith("RCPT TO:")) {
- await send(RESPONSES["RCPT"]);
+ await send(this.#responses["RCPT"]);
} else if (upperLine === "DATA") {
- await send(RESPONSES["DATA"]);
- log.info("Begin to receive mail data...");
+ await send(this.#responses["DATA"]);
+ this.#logger.info("Begin to receive mail data...");
rawMail = "";
} else if (upperLine === "QUIT") {
- await send(RESPONSES["QUIT"]);
+ await send(this.#responses["QUIT"]);
return;
} else {
- log.warn("Smtp server command unrecognized:", line);
- await send(RESPONSES["INVALID"]);
+ this.#logger.warn("Smtp server command unrecognized:", line);
+ await send(this.#responses["INVALID"]);
return;
}
} else {
if (line === ".") {
try {
- log.info("Done receiving mail data, begin to relay...");
+ this.#logger.info("Done receiving mail data, begin to relay...");
const { message } = await this.#deliverer.deliverRaw(rawMail);
await send(`250 2.6.0 ${message}`);
rawMail = null;
- log.info("Done SMTP mail session.");
+ this.#logger.info("Done SMTP mail session.");
} catch (err) {
- log.info(err);
+ this.#logger.info(err);
await send("554 5.3.0 Error: check server log");
return;
}
@@ -100,19 +107,21 @@ export class DumbSmtpServer {
}
}
- async serve() {
- const listener = Deno.listen({
- hostname: config.SMTP_HOST,
- port: config.SMTP_PORT,
- });
- listener.unref();
- log.info(`Dumb SMTP server starts running on port ${config.SMTP_PORT}.`);
+ async serve(options: {
+ hostname: string,
+ port: number
+ }) {
+ const listener = Deno.listen(options);
+ this.#responses = createResponses(options.hostname, options.port);
+ this.#logger.info(
+ `Dumb SMTP server starts running on ${this.#responses.serverName}.`,
+ );
for await (const conn of listener) {
try {
await this.#handleConnection(conn);
} catch (cause) {
- log.error("One smtp connection session throws an error " + cause);
+ this.#logger.error("One smtp connection session throws an error " + cause);
}
}
}