diff options
Diffstat (limited to 'deno/mail-relay/dovecot.ts')
-rw-r--r-- | deno/mail-relay/dovecot.ts | 85 |
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."); + } + } } |