aboutsummaryrefslogtreecommitdiff
path: root/deno/mail-relay/dovecot.ts
diff options
context:
space:
mode:
Diffstat (limited to 'deno/mail-relay/dovecot.ts')
-rw-r--r--deno/mail-relay/dovecot.ts85
1 files changed, 84 insertions, 1 deletions
diff --git a/deno/mail-relay/dovecot.ts b/deno/mail-relay/dovecot.ts
index bace225..6d291ee 100644
--- a/deno/mail-relay/dovecot.ts
+++ b/deno/mail-relay/dovecot.ts
@@ -8,11 +8,17 @@ export class DovecotMailDeliverer extends MailDeliverer {
readonly name = "dovecot";
readonly #logFileProvider;
readonly #ldaPath;
+ readonly #doveadmPath;
- constructor(logFileProvider: LogFileProvider, ldaPath: string) {
+ constructor(
+ logFileProvider: LogFileProvider,
+ ldaPath: string,
+ doveadmPath: string,
+ ) {
super();
this.#logFileProvider = logFileProvider;
this.#ldaPath = ldaPath;
+ this.#doveadmPath = doveadmPath;
}
protected override async doDeliver(
@@ -96,4 +102,81 @@ export class DovecotMailDeliverer extends MailDeliverer {
console.info("Done handling all recipients.");
}
+
+ async #deleteMail(
+ user: string,
+ mailbox: string,
+ messageId: string,
+ ): Promise<void> {
+ try {
+ const args = [
+ "expunge",
+ "-u",
+ user,
+ "mailbox",
+ mailbox,
+ "header",
+ "Message-ID",
+ `<${messageId}>`,
+ ];
+ console.info(
+ `Run external command ${this.#doveadmPath} ${args.join(" ")} ...`,
+ );
+ const command = new Deno.Command(this.#doveadmPath, { args });
+ const status = await command.spawn().status;
+ if (status.success) {
+ console.info("Expunged successfully.");
+ } else {
+ console.warn("Expunging failed with exit code %d.", status.code);
+ }
+ } catch (cause) {
+ console.warn("Expunging failed with an error thrown: ", cause);
+ }
+ }
+
+ async #saveMail(user: string, mailbox: string, mail: Uint8Array) {
+ try {
+ const args = ["save", "-u", user, "-m", mailbox];
+ console.info(
+ `Run external command ${this.#doveadmPath} ${args.join(" ")} ...`,
+ );
+ const command = new Deno.Command(this.#doveadmPath, {
+ args,
+ stdin: "piped",
+ });
+ const process = command.spawn();
+ const stdinWriter = process.stdin.getWriter();
+ await stdinWriter.write(mail);
+ await stdinWriter.close();
+ const status = await process.status;
+
+ if (status.success) {
+ console.info("Saved successfully.");
+ } else {
+ console.warn("Saving failed with exit code %d.", status.code);
+ }
+ } catch (cause) {
+ console.warn("Saving failed with an error thrown: ", cause);
+ }
+ }
+
+ async saveNewSent(originalMessageId: string, mail: Mail) {
+ console.info(
+ "Try to save mail with new id and delete mail with old id in Sent box.",
+ );
+ const from = mail.startSimpleParse().sections().headers()
+ .from();
+ if (from != null) {
+ console.info("Parsed sender (from): ", from);
+ await this.#saveMail(from, "Sent", mail.toUtf8Bytes());
+ setTimeout(() => {
+ console.info(
+ "Try to delete mail in Sent box that has old message id.",
+ );
+ this.#deleteMail(from, "Sent", originalMessageId);
+ }, 1000 * 15);
+ } else {
+ console.warn("Failed to determine from.");
+ }
+ }
}