aboutsummaryrefslogtreecommitdiff
path: root/deno/mail-relay/dovecot.ts
diff options
context:
space:
mode:
authorYuqian Yang <crupest@crupest.life>2025-06-17 19:04:16 +0800
committerYuqian Yang <crupest@crupest.life>2025-06-17 21:37:43 +0800
commit874c4a8babc5aac7214e71dfef7743bae23893a3 (patch)
treed7d39313a442bac49859669bb8d1919267575023 /deno/mail-relay/dovecot.ts
parent0824de3bae3550674a9ea029b03c5cb8a35cd8e1 (diff)
downloadcrupest-874c4a8babc5aac7214e71dfef7743bae23893a3.tar.gz
crupest-874c4a8babc5aac7214e71dfef7743bae23893a3.tar.bz2
crupest-874c4a8babc5aac7214e71dfef7743bae23893a3.zip
HALF WORK!:mail
Diffstat (limited to 'deno/mail-relay/dovecot.ts')
-rw-r--r--deno/mail-relay/dovecot.ts55
1 files changed, 17 insertions, 38 deletions
diff --git a/deno/mail-relay/dovecot.ts b/deno/mail-relay/dovecot.ts
index 55e1e9b..8e6e754 100644
--- a/deno/mail-relay/dovecot.ts
+++ b/deno/mail-relay/dovecot.ts
@@ -16,10 +16,11 @@ async function runCommand(
options: {
args: string[];
stdin?: Uint8Array;
+ suppressResultLog?: boolean;
errorCodeMessageMap?: Map<number, string>;
},
): Promise<CommandResult> {
- const { args, stdin, errorCodeMessageMap } = options;
+ const { args, stdin, suppressResultLog, errorCodeMessageMap } = options;
console.info(`Run external command ${bin} ${args.join(" ")}`);
@@ -33,7 +34,6 @@ async function runCommand(
// Write stdin if any.
if (stdin != null) {
- console.info("Write stdin...");
const writer = process.stdin.getWriter();
await writer.write(stdin);
writer.close();
@@ -43,13 +43,13 @@ async function runCommand(
const status = await process.status;
// Build log message string.
- let message = `Command exited with code ${status.code}`;
+ let message = `External command exited with code ${status.code}`;
if (status.signal != null) message += ` (signal: ${status.signal})`;
if (errorCodeMessageMap != null && errorCodeMessageMap.has(status.code)) {
message += `, ${errorCodeMessageMap.get(status.code)}`;
}
message += ".";
- console.log(message);
+ suppressResultLog || console.log(message);
// Return result.
return {
@@ -58,8 +58,8 @@ async function runCommand(
logMessage: message,
};
} catch (cause) {
- const message = "Running command threw an error:";
- console.log(message, cause);
+ const message = `A JS error was thrown when invoking external command:`;
+ suppressResultLog || console.log(message, cause);
return { kind: "throw", cause, logMessage: message + " " + cause };
}
}
@@ -87,36 +87,34 @@ export class DovecotMailDeliverer extends MailDeliverer {
const recipients = [...context.recipients];
if (recipients.length === 0) {
- context.result.smtpMessage =
- "Failed to deliver to dovecot, no recipients are specified.";
- return;
+ throw new Error(
+ "Failed to deliver to dovecot, no recipients are specified.",
+ );
}
- console.info(`Deliver to dovecot users: ${recipients.join(", ")}.`);
-
for (const recipient of recipients) {
const result = await runCommand(
this.#ldaPath,
{
args: ["-d", recipient],
stdin: utf8Bytes,
+ suppressResultLog: true,
+ errorCodeMessageMap: ldaExitCodeMessageMap,
},
);
if (result.kind === "exit-success") {
context.result.recipients.set(recipient, {
- kind: "done",
+ kind: "success",
message: result.logMessage,
});
} else {
context.result.recipients.set(recipient, {
- kind: "fail",
+ kind: "failure",
message: result.logMessage,
});
}
}
-
- console.info("Done handling all recipients.");
}
#queryArgs(mailbox: string, messageId: string) {
@@ -128,16 +126,12 @@ export class DovecotMailDeliverer extends MailDeliverer {
mailbox: string,
messageId: string,
): Promise<void> {
- console.info(
- `Find and delete mails (user: ${user}, message-id: ${messageId}, mailbox: ${mailbox}).`,
- );
await runCommand(this.#doveadmPath, {
args: ["expunge", "-u", user, ...this.#queryArgs(mailbox, messageId)],
});
}
async #saveMail(user: string, mailbox: string, mail: Uint8Array) {
- console.info(`Save a mail (user: ${user}, mailbox: ${mailbox}).`);
await runCommand(this.#doveadmPath, {
args: ["save", "-u", user, "-m", mailbox],
stdin: mail,
@@ -145,9 +139,6 @@ export class DovecotMailDeliverer extends MailDeliverer {
}
async #markAsRead(user: string, mailbox: string, messageId: string) {
- console.info(
- `Mark mails as \\Seen(user: ${user}, message-id: ${messageId}, mailbox: ${mailbox}, user: ${user}).`,
- );
await runCommand(this.#doveadmPath, {
args: [
"flags",
@@ -164,45 +155,33 @@ export class DovecotMailDeliverer extends MailDeliverer {
console.info("Save sent mails and delete ones with old message id.");
// Try to get from and recipients from headers.
- const headers = mail.startSimpleParse().sections().headers();
- const from = headers.from(),
- recipients = headers.recipients(),
- messageId = headers.messageId();
+ const { messageId, from, recipients } = mail.parsed;
if (from == null) {
- console.warn("Failed to determine from from headers, skip saving.");
+ console.warn("Failed to get sender (from) in headers, skip saving.");
return;
}
- console.info("Parsed from: ", from);
-
if (recipients.has(from)) {
// So the mail should lie in the Inbox.
console.info(
- "The mail has the sender itself as one of recipients, skip saving.",
+ "One recipient of the mail is the sender itself, skip saving.",
);
return;
}
await this.#saveMail(from, "Sent", mail.toUtf8Bytes());
if (messageId != null) {
- console.info("Mark sent mail as read.");
await this.#markAsRead(from, "Sent", messageId);
} else {
console.warn(
- "New message id of the mail is not found, skip marking as read.",
+ "Message id of the mail is not found, skip marking as read.",
);
}
console.info("Schedule deletion of old mails at 15,30,60 seconds later.");
[15, 30, 60].forEach((seconds) =>
setTimeout(() => {
- console.info(
- `Try to delete mails in Sent. (message-id: ${messageIdToDelete}, ` +
- `attempt delay: ${seconds}s) ` +
- "Note that the mail may have already been deleted," +
- " in which case failures of deletion can be just ignored.",
- );
void this.#deleteMail(from, "Sent", messageIdToDelete);
}, 1000 * seconds)
);