diff options
| author | Yuqian Yang <crupest@crupest.life> | 2025-06-14 01:21:11 +0800 | 
|---|---|---|
| committer | Yuqian Yang <crupest@crupest.life> | 2025-06-14 02:35:01 +0800 | 
| commit | 8fe85fccf3881114202301ac986073564d5abd3f (patch) | |
| tree | fc58511731fd77296e3f1df54478bb0208e5fcc5 /deno/mail-relay | |
| parent | 42526fed6f86a3a3a352313078668fcc8b473a3b (diff) | |
| download | crupest-8fe85fccf3881114202301ac986073564d5abd3f.tar.gz crupest-8fe85fccf3881114202301ac986073564d5abd3f.tar.bz2 crupest-8fe85fccf3881114202301ac986073564d5abd3f.zip  | |
deno(mail-server): drop custom logger, use builtin console.
Diffstat (limited to 'deno/mail-relay')
| -rw-r--r-- | deno/mail-relay/app.ts | 21 | ||||
| -rw-r--r-- | deno/mail-relay/aws/app.ts | 27 | ||||
| -rw-r--r-- | deno/mail-relay/aws/deliver.ts | 15 | ||||
| -rw-r--r-- | deno/mail-relay/aws/fetch.ts | 35 | ||||
| -rw-r--r-- | deno/mail-relay/aws/mail.ts | 22 | ||||
| -rw-r--r-- | deno/mail-relay/dovecot.ts | 12 | ||||
| -rw-r--r-- | deno/mail-relay/dumb-smtp-server.ts | 37 | ||||
| -rw-r--r-- | deno/mail-relay/mail.test.ts | 4 | ||||
| -rw-r--r-- | deno/mail-relay/mail.ts | 63 | 
9 files changed, 92 insertions, 144 deletions
diff --git a/deno/mail-relay/app.ts b/deno/mail-relay/app.ts index d96fa1d..0b9da07 100644 --- a/deno/mail-relay/app.ts +++ b/deno/mail-relay/app.ts @@ -35,15 +35,11 @@ export function createInbound(    return deliverer;  } -export function createHono( -  logger: Logger, -  outbound: MailDeliverer, -  inbound: MailDeliverer, -) { +export function createHono(outbound: MailDeliverer, inbound: MailDeliverer) {    const hono = new Hono();    hono.onError((err, c) => { -    logger.error("Hono handler throws an error.", err); +    console.error("Hono handler throws an error.", err);      return c.json({ msg: "Server error, check its log." }, 500);    });    hono.use(honoLogger()); @@ -66,11 +62,11 @@ export function createHono(    return hono;  } -export function createSmtp(logger: Logger, outbound: MailDeliverer) { -  return new DumbSmtpServer(logger, outbound); +export function createSmtp(outbound: MailDeliverer) { +  return new DumbSmtpServer(outbound);  } -export async function sendMail(logger: Logger, port: number) { +export async function sendMail(port: number) {    const decoder = new TextDecoder();    let text = "";    for await (const chunk of Deno.stdin.readable) { @@ -81,9 +77,8 @@ export async function sendMail(logger: Logger, port: number) {      method: "post",      body: text,    }); -  logger.write(Deno.inspect(res), { level: res.ok ? "info" : "error" }); -  logger.write(Deno.inspect(await res.text()), { -    level: res.ok ? "info" : "error", -  }); +  const fn = res.ok ? "info" : "error"; +  console[fn](res); +  console[fn](await res.text());    if (!res.ok) Deno.exit(-1);  } diff --git a/deno/mail-relay/aws/app.ts b/deno/mail-relay/aws/app.ts index 05d93cd..b7d0154 100644 --- a/deno/mail-relay/aws/app.ts +++ b/deno/mail-relay/aws/app.ts @@ -94,11 +94,10 @@ function createAwsOptions({  }  function createOutbound( -  logger: Logger,    awsOptions: ReturnType<typeof createAwsOptions>,    db: DbService,  ) { -  const deliverer = new AwsMailDeliverer(logger, awsOptions); +  const deliverer = new AwsMailDeliverer(awsOptions);    deliverer.preHooks.push(      new AwsMailMessageIdRewriteHook(db.messageIdToAws.bind(db)),    ); @@ -168,11 +167,7 @@ function createAwsFetchOnlyServices() {      password: config.get("awsPassword"),      region: config.get("awsRegion"),    }); -  const fetcher = new AwsMailFetcher( -    logger, -    awsOptions, -    config.get("awsMailBucket"), -  ); +  const fetcher = new AwsMailFetcher(awsOptions, config.get("awsMailBucket"));    return { config, logger, awsOptions, fetcher };  } @@ -195,7 +190,7 @@ function createAwsServices() {    const { config, logger, inbound, awsOptions, fetcher, recycler } =      createAwsRecycleOnlyServices();    const dbService = new DbService(join(config.get("dataPath"), "db.sqlite")); -  const outbound = createOutbound(logger, awsOptions, dbService); +  const outbound = createOutbound(awsOptions, dbService);    return {      config, @@ -211,10 +206,10 @@ function createAwsServices() {  function createServerServices() {    const services = createAwsServices(); -  const { logger, config, outbound, inbound, fetcher } = services; -  const smtp = createSmtp(logger, outbound); +  const { config, outbound, inbound, fetcher } = services; +  const smtp = createSmtp(outbound); -  const hono = createHono(logger, outbound, inbound); +  const hono = createHono(outbound, inbound);    setupAwsHono(hono, {      path: config.get("awsInboundPath"),      auth: config.get("awsInboundKey"), @@ -252,11 +247,11 @@ function serve(cron: boolean = false) {  }  async function listLives() { -  const { logger, fetcher } = createAwsFetchOnlyServices(); +  const { fetcher } = createAwsFetchOnlyServices();    const liveMails = await fetcher.listLiveMails(); -  logger.info(`Total ${liveMails.length}:`); +  console.info(`Total ${liveMails.length}:`);    if (liveMails.length !== 0) { -    logger.info(liveMails.join("\n")); +    console.info(liveMails.join("\n"));    }  } @@ -272,8 +267,8 @@ if (import.meta.main) {        command: "sendmail",        describe: "send mail via this server's endpoint",        handler: async (_argv) => { -        const { logger, config } = createBaseServices(); -        await sendMail(logger, config.getInt("httpPort")); +        const { config } = createBaseServices(); +        await sendMail(config.getInt("httpPort"));        },      })      .command({ diff --git a/deno/mail-relay/aws/deliver.ts b/deno/mail-relay/aws/deliver.ts index 117e87a..a002eda 100644 --- a/deno/mail-relay/aws/deliver.ts +++ b/deno/mail-relay/aws/deliver.ts @@ -4,7 +4,6 @@ import {    SESv2ClientConfig,  } from "@aws-sdk/client-sesv2"; -import { Logger } from "@crupest/base/log";  import { Mail, MailDeliverContext, SyncMailDeliverer } from "../mail.ts";  declare module "../mail.ts" { @@ -15,13 +14,11 @@ declare module "../mail.ts" {  export class AwsMailDeliverer extends SyncMailDeliverer {    readonly name = "aws"; -  readonly #logger;    readonly #aws;    readonly #ses; -  constructor(logger: Logger, aws: SESv2ClientConfig) { -    super(logger); -    this.#logger = logger; +  constructor(aws: SESv2ClientConfig) { +    super();      this.#aws = aws;      this.#ses = new SESv2Client(aws);    } @@ -30,7 +27,7 @@ export class AwsMailDeliverer extends SyncMailDeliverer {      mail: Mail,      context: MailDeliverContext,    ): Promise<void> { -    this.#logger.info("Begin to call aws send-email api..."); +    console.info("Begin to call aws send-email api...");      try {        const sendCommand = new SendEmailCommand({ @@ -41,9 +38,11 @@ export class AwsMailDeliverer extends SyncMailDeliverer {        const res = await this.#ses.send(sendCommand);        if (res.MessageId == null) { -        this.#logger.warn("Aws send-email returns no message id."); +        console.warn("Aws send-email returns no message id.");        } else { -        context.result.awsMessageId = `${res.MessageId}@${this.#aws.region}.amazonses.com`; +        context.result.awsMessageId = `${res.MessageId}@${ +          this.#aws.region +        }.amazonses.com`;        }        context.result.recipients.set("*", { diff --git a/deno/mail-relay/aws/fetch.ts b/deno/mail-relay/aws/fetch.ts index ef1ba5f..bbb671a 100644 --- a/deno/mail-relay/aws/fetch.ts +++ b/deno/mail-relay/aws/fetch.ts @@ -8,7 +8,6 @@ import {  } from "@aws-sdk/client-s3";  import { toFileNameString } from "@crupest/base/date"; -import { Logger } from "@crupest/base/log";  import { Mail } from "../mail.ts"; @@ -42,18 +41,16 @@ export type AwsS3MailConsumer = (  export class AwsMailFetcher {    readonly #livePrefix = "mail/live/";    readonly #archivePrefix = "mail/archive/"; -  readonly #logger;    readonly #s3;    readonly #bucket; -  constructor(logger: Logger, aws: S3ClientConfig, bucket: string) { -    this.#logger = logger; +  constructor(aws: S3ClientConfig, bucket: string) {      this.#s3 = new S3Client(aws);      this.#bucket = bucket;    }    async listLiveMails(): Promise<string[]> { -    this.#logger.info("Begin to retrieve live mails."); +    console.info("Begin to retrieve live mails.");      const listCommand = new ListObjectsV2Command({        Bucket: this.#bucket, @@ -62,16 +59,14 @@ export class AwsMailFetcher {      const res = await this.#s3.send(listCommand);      if (res.Contents == null) { -      this.#logger.warn("Listing live mails in S3 returns null Content."); +      console.warn("Listing live mails in S3 returns null Content.");        return [];      }      const result: string[] = [];      for (const object of res.Contents) {        if (object.Key == null) { -        this.#logger.warn( -          "Listing live mails in S3 returns an object with no Key.", -        ); +        console.warn("Listing live mails in S3 returns an object with no Key.");          continue;        } @@ -83,9 +78,9 @@ export class AwsMailFetcher {    }    async consumeS3Mail(s3Key: string, consumer: AwsS3MailConsumer) { -    this.#logger.info(`Begin to consume s3 mail ${s3Key} ...`); +    console.info(`Begin to consume s3 mail ${s3Key} ...`); -    this.#logger.info(`Fetching s3 mail ${s3Key}...`); +    console.info(`Fetching s3 mail ${s3Key}...`);      const mailPath = `${this.#livePrefix}${s3Key}`;      const command = new GetObjectCommand({        Bucket: this.#bucket, @@ -98,14 +93,14 @@ export class AwsMailFetcher {      }      const rawMail = await res.Body.transformToString(); -    this.#logger.info(`Done fetching s3 mail ${s3Key}.`); +    console.info(`Done fetching s3 mail ${s3Key}.`); -    this.#logger.info(`Calling consumer...`); +    console.info(`Calling consumer...`);      await consumer(rawMail, s3Key); -    this.#logger.info(`Done consuming s3 mail ${s3Key}.`); +    console.info(`Done consuming s3 mail ${s3Key}.`);      const date = new Mail(rawMail) -      .startSimpleParse(this.#logger) +      .startSimpleParse()        .sections()        .headers()        .date(); @@ -113,17 +108,17 @@ export class AwsMailFetcher {        date != null ? toFileNameString(date, true) : "invalid-date";      const newPath = `${this.#archivePrefix}${dateString}/${s3Key}`; -    this.#logger.info(`Archiving s3 mail ${s3Key} to ${newPath}...`); +    console.info(`Archiving s3 mail ${s3Key} to ${newPath}...`);      await s3MoveObject(this.#s3, this.#bucket, mailPath, newPath); -    this.#logger.info(`Done archiving s3 mail ${s3Key}.`); +    console.info(`Done archiving s3 mail ${s3Key}.`); -    this.#logger.info(`Done consuming s3 mail ${s3Key}.`); +    console.info(`Done consuming s3 mail ${s3Key}.`);    }    async recycleLiveMails(consumer: AwsS3MailConsumer) { -    this.#logger.info("Begin to recycle live mails..."); +    console.info("Begin to recycle live mails...");      const mails = await this.listLiveMails(); -    this.#logger.info(`Found ${mails.length} live mails`); +    console.info(`Found ${mails.length} live mails`);      for (const s3Key of mails) {        await this.consumeS3Mail(s3Key, consumer);      } diff --git a/deno/mail-relay/aws/mail.ts b/deno/mail-relay/aws/mail.ts index d2cfad1..cc05d23 100644 --- a/deno/mail-relay/aws/mail.ts +++ b/deno/mail-relay/aws/mail.ts @@ -8,17 +8,17 @@ export class AwsMailMessageIdRewriteHook implements MailDeliverHook {    }    async callback(context: MailDeliverContext): Promise<void> { -    context.logger.info("Rewrite message ids..."); +    console.info("Rewrite message ids...");      const addresses = context.mail.simpleFindAllAddresses(); -    context.logger.info(`Addresses found in mail: ${addresses.join(", ")}.`); +    console.info(`Addresses found in mail: ${addresses.join(", ")}.`);      for (const address of addresses) {        const awsMessageId = await this.#lookup(address);        if (awsMessageId != null && awsMessageId.length !== 0) { -        context.logger.info(`Rewrite ${address} to ${awsMessageId}.`); +        console.info(`Rewrite ${address} to ${awsMessageId}.`);          context.mail.raw = context.mail.raw.replaceAll(address, awsMessageId);        }      } -    context.logger.info("Done rewrite message ids."); +    console.info("Done rewrite message ids.");    }  } @@ -30,24 +30,20 @@ export class AwsMailMessageIdSaveHook implements MailDeliverHook {    }    async callback(context: MailDeliverContext): Promise<void> { -    context.logger.info("Save aws message ids..."); +    console.info("Save aws message ids...");      const messageId = context.mail -      .startSimpleParse(context.logger) +      .startSimpleParse()        .sections()        .headers()        .messageId();      if (messageId == null) { -      context.logger.info( -        "Original mail does not have message id. Skip saving.", -      ); +      console.info("Original mail does not have message id. Skip saving.");        return;      }      if (context.result.awsMessageId != null) { -      context.logger.info( -        `Saving ${messageId} => ${context.result.awsMessageId}.`, -      ); +      console.info(`Saving ${messageId} => ${context.result.awsMessageId}.`);        await this.#record(messageId, context.result.awsMessageId);      } -    context.logger.info("Done save message ids."); +    console.info("Done save message ids.");    }  } diff --git a/deno/mail-relay/dovecot.ts b/deno/mail-relay/dovecot.ts index 124a82b..748d6fa 100644 --- a/deno/mail-relay/dovecot.ts +++ b/deno/mail-relay/dovecot.ts @@ -6,10 +6,12 @@ import { Mail, MailDeliverContext, MailDeliverer } from "./mail.ts";  export class DovecotMailDeliverer extends MailDeliverer {    readonly name = "dovecot"; +  readonly #logger;    readonly #ldaPath;    constructor(logger: Logger, ldaPath: string) { -    super(logger); +    super(); +    this.#logger = logger;      this.#ldaPath = ldaPath;    } @@ -29,12 +31,12 @@ export class DovecotMailDeliverer extends MailDeliverer {        return;      } -    this.logger.info(`Deliver to dovecot users: ${recipients.join(", ")}.`); +    console.info(`Deliver to dovecot users: ${recipients.join(", ")}.`);      for (const recipient of recipients) {        try {          const commandArgs = ["-d", recipient]; -        this.logger.info(`Run ${ldaBinName} ${commandArgs.join(" ")}...`); +        console.info(`Run ${ldaBinName} ${commandArgs.join(" ")}...`);          const ldaCommand = new Deno.Command(ldaPath, {            args: commandArgs, @@ -45,7 +47,7 @@ export class DovecotMailDeliverer extends MailDeliverer {          const ldaProcess = ldaCommand.spawn();          using logFiles = -          await this.logger.createExternalLogStreamsForProgram(ldaBinName); +          await this.#logger.createExternalLogStreamsForProgram(ldaBinName);          ldaProcess.stdout.pipeTo(logFiles.stdout);          ldaProcess.stderr.pipeTo(logFiles.stderr); @@ -90,6 +92,6 @@ export class DovecotMailDeliverer extends MailDeliverer {        }      } -    this.logger.info("Done handling all recipients."); +    console.info("Done handling all recipients.");    }  } diff --git a/deno/mail-relay/dumb-smtp-server.ts b/deno/mail-relay/dumb-smtp-server.ts index 1a1090a..ac7069c 100644 --- a/deno/mail-relay/dumb-smtp-server.ts +++ b/deno/mail-relay/dumb-smtp-server.ts @@ -1,4 +1,3 @@ -import { Logger } from "@crupest/base/log";  import { MailDeliverer } from "./mail.ts";  const CRLF = "\r\n"; @@ -20,26 +19,24 @@ function createResponses(host: string, port: number | string) {  const LOG_TAG = "[dumb-smtp]";  export class DumbSmtpServer { -  #logger;    #deliverer;    #responses: ReturnType<typeof createResponses> = createResponses(      "invalid",      "invalid",    ); -  constructor(logger: Logger, deliverer: MailDeliverer) { -    this.#logger = logger; +  constructor(deliverer: MailDeliverer) {      this.#deliverer = deliverer;    }    async #handleConnection(conn: Deno.Conn) {      using disposeStack = new DisposableStack();      disposeStack.defer(() => { -      this.#logger.tagInfo(LOG_TAG, "Close session's tcp connection."); +      console.info(LOG_TAG, "Close session's tcp connection.");        conn.close();      }); -    this.#logger.tagInfo(LOG_TAG, "New session's tcp connection established."); +    console.info(LOG_TAG, "New session's tcp connection established.");      const writer = conn.writable.getWriter();      disposeStack.defer(() => writer.releaseLock()); @@ -49,7 +46,7 @@ export class DumbSmtpServer {      const [decoder, encoder] = [new TextDecoder(), new TextEncoder()];      const decode = (data: Uint8Array) => decoder.decode(data);      const send = async (s: string) => { -      this.#logger.tagInfo(LOG_TAG, "Send line: " + s); +      console.info(LOG_TAG, "Send line: " + s);        await writer.write(encoder.encode(s + CRLF));      }; @@ -72,7 +69,7 @@ export class DumbSmtpServer {          buffer = buffer.slice(eolPos + CRLF.length);          if (rawMail == null) { -          this.#logger.tagInfo(LOG_TAG, "Received line: " + line); +          console.info(LOG_TAG, "Received line: " + line);            const upperLine = line.toUpperCase();            if (upperLine.startsWith("EHLO") || upperLine.startsWith("HELO")) {              await send(this.#responses["EHLO"]); @@ -82,32 +79,26 @@ export class DumbSmtpServer {              await send(this.#responses["RCPT"]);            } else if (upperLine === "DATA") {              await send(this.#responses["DATA"]); -            this.#logger.tagInfo(LOG_TAG, "Begin to receive mail data..."); +            console.info(LOG_TAG, "Begin to receive mail data...");              rawMail = "";            } else if (upperLine === "QUIT") {              await send(this.#responses["QUIT"]);              return;            } else { -            this.#logger.tagWarn( -              LOG_TAG, -              "Unrecognized command from client: " + line, -            ); +            console.warn(LOG_TAG, "Unrecognized command from client: " + line);              await send(this.#responses["INVALID"]);              return;            }          } else {            if (line === ".") {              try { -              this.#logger.tagInfo( -                LOG_TAG, -                "Mail data Received, begin to relay...", -              ); +              console.info(LOG_TAG, "Mail data Received, begin to relay...");                const { message } = await this.#deliverer.deliverRaw(rawMail);                await send(`250 2.6.0 ${message}`);                rawMail = null; -              this.#logger.tagInfo(LOG_TAG, "Relay succeeded."); +              console.info(LOG_TAG, "Relay succeeded.");              } catch (err) { -              this.#logger.tagError(LOG_TAG, "Relay failed.", err); +              console.error(LOG_TAG, "Relay failed.", err);                await send("554 5.3.0 Error: check server log");                return;              } @@ -123,7 +114,7 @@ export class DumbSmtpServer {    async serve(options: { hostname: string; port: number }) {      const listener = Deno.listen(options);      this.#responses = createResponses(options.hostname, options.port); -    this.#logger.tagInfo( +    console.info(        LOG_TAG,        `Dumb SMTP server starts to listen on ${this.#responses.serverName}.`,      ); @@ -132,11 +123,7 @@ export class DumbSmtpServer {        try {          await this.#handleConnection(conn);        } catch (cause) { -        this.#logger.tagError( -          LOG_TAG, -          "Tcp connection throws an error.", -          cause, -        ); +        console.error(LOG_TAG, "Tcp connection throws an error.", cause);        }      }    } diff --git a/deno/mail-relay/mail.test.ts b/deno/mail-relay/mail.test.ts index 09cf8eb..6abb7d7 100644 --- a/deno/mail-relay/mail.test.ts +++ b/deno/mail-relay/mail.test.ts @@ -1,8 +1,6 @@  import { describe, it } from "@std/testing/bdd";  import { expect, fn } from "@std/expect"; -import { Logger } from "@crupest/base/log"; -  import { Mail, MailDeliverContext, MailDeliverer } from "./mail.ts";  const mockDate = "Fri, 02 May 2025 08:33:02 +0000"; @@ -119,7 +117,7 @@ describe("MailDeliverer", () => {        return Promise.resolve();      }) as MailDeliverer["doDeliver"];    } -  const mockDeliverer = new MockMailDeliverer(new Logger()); +  const mockDeliverer = new MockMailDeliverer();    it("deliver success", async () => {      await mockDeliverer.deliverRaw(mockMailStr); diff --git a/deno/mail-relay/mail.ts b/deno/mail-relay/mail.ts index 12d5972..d6dfe65 100644 --- a/deno/mail-relay/mail.ts +++ b/deno/mail-relay/mail.ts @@ -2,19 +2,10 @@ import { encodeBase64 } from "@std/encoding/base64";  import { parse } from "@std/csv/parse";  import emailAddresses from "email-addresses"; -import { Logger } from "@crupest/base/log"; -  class MailSimpleParseError extends Error {}  class MailSimpleParsedHeaders { -  #logger; - -  constructor( -    logger: Logger | undefined, -    public fields: [key: string, value: string][], -  ) { -    this.#logger = logger; -  } +  constructor(public fields: [key: string, value: string][]) {}    getFirst(fieldKey: string): string | undefined {      for (const [key, value] of this.fields) { @@ -31,9 +22,7 @@ class MailSimpleParsedHeaders {      if (match != null) {        return match[1];      } else { -      this.#logger?.warn( -        "Invalid message-id header of mail: " + messageIdField, -      ); +      console.warn("Invalid message-id header of mail: " + messageIdField);        return undefined;      }    } @@ -44,7 +33,7 @@ class MailSimpleParsedHeaders {      const date = new Date(dateField);      if (invalidToUndefined && isNaN(date.getTime())) { -      this.#logger?.warn(`Invalid date string (${dateField}) found in header.`); +      console.warn(`Invalid date string (${dateField}) found in header.`);        return undefined;      }      return date; @@ -76,11 +65,7 @@ class MailSimpleParsedSections {    eol: string;    sep: string; -  #logger; - -  constructor(logger: Logger | undefined, raw: string) { -    this.#logger = logger; - +  constructor(raw: string) {      const twoEolMatch = raw.match(/(\r?\n)(\r?\n)/);      if (twoEolMatch == null) {        throw new MailSimpleParseError( @@ -91,7 +76,7 @@ class MailSimpleParsedSections {      const [eol, sep] = [twoEolMatch[1], twoEolMatch[2]];      if (eol !== sep) { -      logger?.warn("Different EOLs (\\r\\n, \\n) found."); +      console.warn("Different EOLs (\\r\\n, \\n) found.");      }      this.header = raw.slice(0, twoEolMatch.index!); @@ -131,7 +116,7 @@ class MailSimpleParsedSections {      handleField(); -    return new MailSimpleParsedHeaders(this.#logger, headers); +    return new MailSimpleParsedHeaders(headers);    }  } @@ -147,8 +132,8 @@ export class Mail {      return encodeBase64(this.raw);    } -  startSimpleParse(logger?: Logger) { -    return { sections: () => new MailSimpleParsedSections(logger, this.raw) }; +  startSimpleParse() { +    return { sections: () => new MailSimpleParsedSections(this.raw) };    }    simpleFindAllAddresses(): string[] { @@ -195,10 +180,7 @@ export class MailDeliverContext {    readonly recipients: Set<string> = new Set();    readonly result; -  constructor( -    public readonly logger: Logger, -    public mail: Mail, -  ) { +  constructor(public mail: Mail) {      this.result = new MailDeliverResult(this.mail);    }  } @@ -212,8 +194,6 @@ export abstract class MailDeliverer {    preHooks: MailDeliverHook[] = [];    postHooks: MailDeliverHook[] = []; -  constructor(protected readonly logger: Logger) {} -    protected abstract doDeliver(      mail: Mail,      context: MailDeliverContext, @@ -227,9 +207,9 @@ export abstract class MailDeliverer {      mail: Mail;      recipients?: string[];    }): Promise<MailDeliverResult> { -    this.logger.info(`Begin to deliver mail via ${this.name}...`); +    console.info(`Begin to deliver mail via ${this.name}...`); -    const context = new MailDeliverContext(this.logger, options.mail); +    const context = new MailDeliverContext(options.mail);      options.recipients?.forEach((r) => context.recipients.add(r));      for (const hook of this.preHooks) { @@ -242,7 +222,8 @@ export abstract class MailDeliverer {        await hook.callback(context);      } -    context.logger.info("Deliver result:\n" + Deno.inspect(context.result)); +    console.info("Deliver result:"); +    console.info(context.result);      if (context.result.hasError()) {        throw new Error("Mail failed to deliver."); @@ -259,7 +240,7 @@ export abstract class SyncMailDeliverer extends MailDeliverer {      mail: Mail;      recipients?: string[];    }): Promise<MailDeliverResult> { -    this.logger.info( +    console.info(        "The mail deliverer is sync. Wait for last delivering done...",      );      await this.#last; @@ -277,12 +258,12 @@ export class RecipientFromHeadersHook implements MailDeliverHook {    callback(context: MailDeliverContext) {      if (context.recipients.size !== 0) { -      context.logger.warn( +      console.warn(          "Recipients are already filled. Won't set them with ones in headers.",        );      } else {        context.mail -        .startSimpleParse(context.logger) +        .startSimpleParse()          .sections()          .headers()          .recipients({ @@ -290,7 +271,7 @@ export class RecipientFromHeadersHook implements MailDeliverHook {          })          .forEach((r) => context.recipients.add(r)); -      context.logger.info( +      console.info(          "Recipients found from mail headers: " +            [...context.recipients].join(", "),        ); @@ -304,7 +285,7 @@ export class FallbackRecipientHook implements MailDeliverHook {    callback(context: MailDeliverContext) {      if (context.recipients.size === 0) { -      context.logger.info( +      console.info(          "No recipients, fill with fallback: " + [...this.fallback].join(", "),        );        this.fallback.forEach((a) => context.recipients.add(a)); @@ -320,10 +301,10 @@ export class AliasRecipientMailHook implements MailDeliverHook {      this.#aliasFile = aliasFile;    } -  async #parseAliasFile(logger: Logger): Promise<Map<string, string>> { +  async #parseAliasFile(): Promise<Map<string, string>> {      const result = new Map();      if ((await Deno.stat(this.#aliasFile)).isFile) { -      logger.info(`Found recipients alias file: ${this.#aliasFile}.`); +      console.info(`Found recipients alias file: ${this.#aliasFile}.`);        const text = await Deno.readTextFile(this.#aliasFile);        const csv = parse(text);        for (const [real, ...aliases] of csv) { @@ -334,11 +315,11 @@ export class AliasRecipientMailHook implements MailDeliverHook {    }    async callback(context: MailDeliverContext) { -    const aliases = await this.#parseAliasFile(context.logger); +    const aliases = await this.#parseAliasFile();      for (const recipient of [...context.recipients]) {        const realRecipients = aliases.get(recipient);        if (realRecipients != null) { -        context.logger.info( +        console.info(            `Recipient alias resolved: ${recipient} => ${realRecipients}.`,          );          context.recipients.delete(recipient);  | 
