diff --git a/app/logic/Mail/ActiveSync/ActiveSyncAccount.ts b/app/logic/Mail/ActiveSync/ActiveSyncAccount.ts index 77be7ed34..441b29b83 100644 --- a/app/logic/Mail/ActiveSync/ActiveSyncAccount.ts +++ b/app/logic/Mail/ActiveSync/ActiveSyncAccount.ts @@ -1,8 +1,7 @@ -import { AuthMethod, MailAccount, TLSSocketType } from "../MailAccount"; +import { AuthMethod, MailAccount, TLSSocketType, NMUtils } from "../MailAccount"; import type { EMail } from "../EMail"; import { kMaxCount, ActiveSyncFolder, FolderType } from "./ActiveSyncFolder"; import { ActiveSyncError } from "./ActiveSyncError"; -import { SMTPAccount } from "../SMTP/SMTPAccount"; import { newAddressbookForProtocol} from "../../Contacts/AccountsList/Addressbooks"; import type { ActiveSyncAddressbook } from "../../Contacts/ActiveSync/ActiveSyncAddressbook"; import { newCalendarForProtocol} from "../../Calendar/AccountsList/Calendars"; @@ -119,7 +118,7 @@ export class ActiveSyncAccount extends MailAccount { let request = { ClientId: await this.nextClientID(), SaveInSentItems: {}, - Mime: await SMTPAccount.getMIME(email), + Mime: await NMUtils.getMIME(email), }; await this.callEAS("SendMail", request); } diff --git a/app/logic/Mail/EMail.ts b/app/logic/Mail/EMail.ts index 2b3dee29e..25712439c 100644 --- a/app/logic/Mail/EMail.ts +++ b/app/logic/Mail/EMail.ts @@ -2,7 +2,7 @@ import { Message } from "../Abstract/Message"; import { SpecialFolder, type Folder } from "./Folder"; import { Attachment, ContentDisposition } from "./Attachment"; import type { Tag } from "./Tag"; -import { DeleteStrategy, type MailAccountStorage } from "./MailAccount"; +import { DeleteStrategy, NMUtils, type MailAccountStorage } from "./MailAccount"; import { PersonUID, findOrCreatePersonUID } from "../Abstract/PersonUID"; import { MailIdentity } from "./MailIdentity"; import { Event } from "../Calendar/Event"; @@ -412,7 +412,7 @@ export class EMail extends Message { async download() { throw new AbstractFunction(); - //this.mime = await SMTPAccount.getMIME(this); + //this.mime = await NMUtils.getMIME(this); } async findThread(messages: Collection): Promise{ @@ -607,8 +607,7 @@ export class EMailActions { } let previousDraft = this.getDraftOnServer(); - return; // TODO - this.email.mime = await appGlobal.remoteApp.getMIMENodemailer(this.email); + this.email.mime = await NMUtils.getMIME(this.email); await draftFolder.addMessage(this.email); previousDraft?.deleteMessage(); } diff --git a/app/logic/Mail/MailAccount.ts b/app/logic/Mail/MailAccount.ts index d2430247c..129aa29b5 100644 --- a/app/logic/Mail/MailAccount.ts +++ b/app/logic/Mail/MailAccount.ts @@ -2,13 +2,18 @@ import { Account } from "../Abstract/Account"; import { MailIdentity } from "./MailIdentity"; import { Folder, SpecialFolder } from "./Folder"; import type { EMail } from "./EMail"; +import { Attachment , ContentDisposition } from "./Attachment"; import type { Person } from "../Abstract/Person"; +import type { PersonUID } from "../Abstract/PersonUID"; import { OAuth2 } from "../Auth/OAuth2"; import { appGlobal } from "../app"; +import { getLocalStorage } from "../../frontend/Util/LocalStorage"; import { sanitize } from "../../../lib/util/sanitizeDatatypes"; -import { AbstractFunction, type URLString } from "../util/util"; +import { blobToBase64, AbstractFunction, type URLString } from "../util/util"; import { notifyChangedProperty } from "../util/Observable"; import { Collection, ArrayColl, MapColl } from 'svelte-collections'; +import type { default as Mail, Attachment as NMAttachment, Address as NMAddress } from "nodemailer/lib/mailer"; +type NMMail = Mail.Options; export class MailAccount extends Account { readonly protocol: string = "mail"; @@ -244,3 +249,55 @@ export class SetupInstruction { enterPassword: boolean = false; enterUsername: boolean = false; } + +export const NMUtils = { + async getNMMail(email: EMail): Promise { + let doHTML = getLocalStorage("mail.send.format", "html").value == "html"; + // + return { + subject: email.subject, + inReplyTo: email.inReplyTo, + from: this.getRecipient(email.from), + replyTo: email.replyTo ? this.getRecipient(email.replyTo) : null, + to: this.getRecipients(email.to), + cc: this.getRecipients(email.cc), + bcc: this.getRecipients(email.bcc), + text: email.text, + html: doHTML ? email.html : null, + attachDataUrls: true, + attachments: await this.getAttachments(email), + headers: email.headers.contentKeyValues(), + disableFileAccess: true, + disableUrlAccess: true, + }; + }, + + async getMIME(email: EMail): Promise { + let mail = await this.getNMMail(email); + return await appGlobal.remoteApp.getMIMENodemailer(mail); + }, + + getRecipients(recipients: ArrayColl): NMAddress[] { + return recipients.contents.map(this.getRecipient); + }, + getRecipient(to: PersonUID): NMAddress { + // `${to.name} <${to.emailAddress}>` created by nodemailer, with quotes + return { + name: to.name, + address: to.emailAddress, + }; + }, + async getAttachments(email: EMail): Promise { + return await Promise.all(email.attachments.contents.map(this.getAttachment)); + }, + async getAttachment(a: Attachment): Promise { + return { + filename: a.filename, + content: await blobToBase64(a.content), + encoding: "base64", + contentType: a.mimeType, + contentDisposition: a.disposition == ContentDisposition.inline ? 'inline' : 'attachment', + cid: a.contentID, + }; + }, +}; diff --git a/app/logic/Mail/SMTP/SMTPAccount.ts b/app/logic/Mail/SMTP/SMTPAccount.ts index d026dac0a..dde342ecf 100644 --- a/app/logic/Mail/SMTP/SMTPAccount.ts +++ b/app/logic/Mail/SMTP/SMTPAccount.ts @@ -1,13 +1,8 @@ -import { MailAccount, TLSSocketType, AuthMethod } from "../MailAccount"; +import { MailAccount, TLSSocketType, AuthMethod, NMUtils } from "../MailAccount"; import type { EMail } from "../EMail"; -import type { PersonUID } from "../../Abstract/PersonUID"; -import { Attachment , ContentDisposition } from "../Attachment"; import { appGlobal } from "../../app"; -import { getLocalStorage } from "../../../frontend/Util/LocalStorage"; -import { blobToBase64, assert } from "../../util/util"; +import { assert } from "../../util/util"; import type { ArrayColl } from "svelte-collections"; -import type { default as Mail, Attachment as NMAttachment, Address as NMAddress } from "nodemailer/lib/mailer"; -type NMMail = Mail.Options; export class SMTPAccount extends MailAccount { readonly protocol: string = "smtp"; @@ -53,7 +48,7 @@ export class SMTPAccount extends MailAccount { async send(email: EMail): Promise { try { - let mail = await SMTPAccount.getNMMail(email); + let mail = await NMUtils.getNMMail(email); let result = await appGlobal.remoteApp.sendMailNodemailer( this.getTransportOptions(), mail); email.sent = new Date(); @@ -68,32 +63,6 @@ export class SMTPAccount extends MailAccount { } } - static async getNMMail(email: EMail): Promise { - let doHTML = getLocalStorage("mail.send.format", "html").value == "html"; - // - return { - subject: email.subject, - inReplyTo: email.inReplyTo, - from: SMTPAccount.getRecipient(email.from), - replyTo: email.replyTo ? SMTPAccount.getRecipient(email.replyTo) : null, - to: SMTPAccount.getRecipients(email.to), - cc: SMTPAccount.getRecipients(email.cc), - bcc: SMTPAccount.getRecipients(email.bcc), - text: email.text, - html: doHTML ? email.html : null, - attachDataUrls: true, - attachments: await SMTPAccount.getAttachments(email), - headers: email.headers.contentKeyValues(), - disableFileAccess: true, - disableUrlAccess: true, - }; - } - - static async getMIME(email: EMail): Promise { - let mail = await SMTPAccount.getNMMail(email); - return await appGlobal.remoteApp.getMIMENodemailer(mail); - } - async verifyLogin(): Promise { try { await appGlobal.remoteApp.verifyServerNodemailer(this.getTransportOptions()); @@ -105,28 +74,4 @@ export class SMTPAccount extends MailAccount { throw ex; } } - - protected static getRecipients(recipients: ArrayColl): NMAddress[] { - return recipients.contents.map(to => SMTPAccount.getRecipient(to)); - } - protected static getRecipient(to: PersonUID): NMAddress { - // `${to.name} <${to.emailAddress}>` created by nodemailer, with quotes - return { - name: to.name, - address: to.emailAddress, - }; - } - protected static async getAttachments(email: EMail): Promise { - return await Promise.all(email.attachments.contents.map((a) => SMTPAccount.getAttachment(a))); - } - protected static async getAttachment(a: Attachment): Promise { - return { - filename: a.filename, - content: await blobToBase64(a.content), - encoding: "base64", - contentType: a.mimeType, - contentDisposition: a.disposition == ContentDisposition.inline ? 'inline' : 'attachment', - cid: a.contentID, - }; - } }