Skip to content

Commit

Permalink
Generate MIME that can be saved as draft #407
Browse files Browse the repository at this point in the history
  • Loading branch information
NeilRashbrook committed Jan 17, 2025
1 parent 20a2fd5 commit 8a58219
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 66 deletions.
5 changes: 2 additions & 3 deletions app/logic/Mail/ActiveSync/ActiveSyncAccount.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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);
}
Expand Down
7 changes: 3 additions & 4 deletions app/logic/Mail/EMail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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<EMail>): Promise<string | null>{
Expand Down Expand Up @@ -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();
}
Expand Down
59 changes: 58 additions & 1 deletion app/logic/Mail/MailAccount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -244,3 +249,55 @@ export class SetupInstruction {
enterPassword: boolean = false;
enterUsername: boolean = false;
}

export const NMUtils = {
async getNMMail(email: EMail): Promise<NMMail> {
let doHTML = getLocalStorage("mail.send.format", "html").value == "html";
// <https://nodemailer.com/message/>
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<Uint8Array> {
let mail = await this.getNMMail(email);
return await appGlobal.remoteApp.getMIMENodemailer(mail);
},

getRecipients(recipients: ArrayColl<PersonUID>): 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<NMAttachment[]> {
return await Promise.all(email.attachments.contents.map(this.getAttachment));
},
async getAttachment(a: Attachment): Promise<NMAttachment> {
return {
filename: a.filename,
content: await blobToBase64(a.content),
encoding: "base64",
contentType: a.mimeType,
contentDisposition: a.disposition == ContentDisposition.inline ? 'inline' : 'attachment',
cid: a.contentID,
};
},
};
61 changes: 3 additions & 58 deletions app/logic/Mail/SMTP/SMTPAccount.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -53,7 +48,7 @@ export class SMTPAccount extends MailAccount {

async send(email: EMail): Promise<void> {
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();
Expand All @@ -68,32 +63,6 @@ export class SMTPAccount extends MailAccount {
}
}

static async getNMMail(email: EMail): Promise<NMMail> {
let doHTML = getLocalStorage("mail.send.format", "html").value == "html";
// <https://nodemailer.com/message/>
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<Uint8Array> {
let mail = await SMTPAccount.getNMMail(email);
return await appGlobal.remoteApp.getMIMENodemailer(mail);
}

async verifyLogin(): Promise<void> {
try {
await appGlobal.remoteApp.verifyServerNodemailer(this.getTransportOptions());
Expand All @@ -105,28 +74,4 @@ export class SMTPAccount extends MailAccount {
throw ex;
}
}

protected static getRecipients(recipients: ArrayColl<PersonUID>): 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<NMAttachment[]> {
return await Promise.all(email.attachments.contents.map((a) => SMTPAccount.getAttachment(a)));
}
protected static async getAttachment(a: Attachment): Promise<NMAttachment> {
return {
filename: a.filename,
content: await blobToBase64(a.content),
encoding: "base64",
contentType: a.mimeType,
contentDisposition: a.disposition == ContentDisposition.inline ? 'inline' : 'attachment',
cid: a.contentID,
};
}
}

0 comments on commit 8a58219

Please sign in to comment.