@social-mail/social-mail-web-server 1.7.78 → 1.7.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/server/model/events/EmailEvents.d.ts.map +1 -1
  2. package/dist/server/model/events/EmailEvents.js +7 -5
  3. package/dist/server/model/events/EmailEvents.js.map +1 -1
  4. package/dist/server/services/email-logs/EmailLogService.d.ts +1 -0
  5. package/dist/server/services/email-logs/EmailLogService.d.ts.map +1 -1
  6. package/dist/server/services/email-logs/EmailLogService.js +66 -0
  7. package/dist/server/services/email-logs/EmailLogService.js.map +1 -1
  8. package/dist/server/workflows/channel/BroadcastEmail.d.ts.map +1 -1
  9. package/dist/server/workflows/channel/BroadcastEmail.js +1 -0
  10. package/dist/server/workflows/channel/BroadcastEmail.js.map +1 -1
  11. package/dist/server/workflows/smtp/DispatchEmailToMX.d.ts +1 -15
  12. package/dist/server/workflows/smtp/DispatchEmailToMX.d.ts.map +1 -1
  13. package/dist/server/workflows/smtp/DispatchEmailToMX.js +11 -2
  14. package/dist/server/workflows/smtp/DispatchEmailToMX.js.map +1 -1
  15. package/dist/server/workflows/smtp/IMessageEnvelope.d.ts +16 -0
  16. package/dist/server/workflows/smtp/IMessageEnvelope.d.ts.map +1 -0
  17. package/dist/server/workflows/smtp/IMessageEnvelope.js +2 -0
  18. package/dist/server/workflows/smtp/IMessageEnvelope.js.map +1 -0
  19. package/dist/server/workflows/smtp/MailDispatcherService.d.ts +5 -12
  20. package/dist/server/workflows/smtp/MailDispatcherService.d.ts.map +1 -1
  21. package/dist/server/workflows/smtp/MailDispatcherService.js +15 -4
  22. package/dist/server/workflows/smtp/MailDispatcherService.js.map +1 -1
  23. package/dist/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +1 -1
  25. package/src/server/model/events/EmailEvents.ts +7 -4
  26. package/src/server/services/email-logs/EmailLogService.ts +8 -0
  27. package/src/server/workflows/channel/BroadcastEmail.ts +1 -0
  28. package/src/server/workflows/smtp/DispatchEmailToMX.ts +15 -20
  29. package/src/server/workflows/smtp/IMessageEnvelope.ts +15 -0
  30. package/src/server/workflows/smtp/MailDispatcherService.ts +22 -6
  31. package/dist/server/workflows/channel/BroadcastEmailToMX.d.ts +0 -2
  32. package/dist/server/workflows/channel/BroadcastEmailToMX.d.ts.map +0 -1
  33. package/dist/server/workflows/channel/BroadcastEmailToMX.js +0 -219
  34. package/dist/server/workflows/channel/BroadcastEmailToMX.js.map +0 -1
  35. package/src/server/workflows/channel/BroadcastEmailToMX.ts +0 -257
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@social-mail/social-mail-web-server",
3
- "version": "1.7.78",
3
+ "version": "1.7.80",
4
4
  "description": "## Phase 1",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -291,10 +291,13 @@ export default class EmailEvents extends AuthenticatedEvents<Email> {
291
291
  }
292
292
 
293
293
  preJson(entity: Email): Email {
294
- if (entity.status === "published") {
295
- this.sessionSecurity.injectPublicKey(entity);
296
- } else {
297
- this.sessionSecurity.injectKey(entity);
294
+ switch(entity.status) {
295
+ case "published":
296
+ this.sessionSecurity.injectPublicKey(entity);
297
+ break;
298
+ default:
299
+ this.sessionSecurity.injectKey(entity);
300
+ break;
298
301
  }
299
302
  entity.statePostReceiveInvoked = void 0;
300
303
  entity.stateReferencesUpdated = void 0;
@@ -36,6 +36,14 @@ export default class EmailLogService {
36
36
  }
37
37
  }
38
38
 
39
+ async delete(logID: number) {
40
+ await using tx = await this.db.connection.createTransaction();
41
+ const log = await this.db.emailLogs.statements.select({}, { logID});
42
+ await this.storage.deleteFile(log.cloudPath);
43
+ await this.db.emailLogs.statements.delete({ logID });
44
+ await tx.commit();
45
+ }
46
+
39
47
  async save(emailID: number, file: LocalFile, compression: string = "gz") {
40
48
  const { db, tfs } = this;
41
49
 
@@ -171,6 +171,7 @@ export default class BroadcastEmail extends Workflow<IBroadcastEmail> {
171
171
  senderID,
172
172
  external: false,
173
173
  doNotSendDR: true,
174
+ saveHeadersOnly: true,
174
175
  activityID,
175
176
  accessCode,
176
177
  from,
@@ -8,18 +8,16 @@ import Tracer from "../../../Tracer.js";
8
8
  import SocialMailContext from "../../model/SocialMailContext.js";
9
9
  import SMTPClient, { ISmtpResponse } from "../../smtp/client/SMTPClient.js";
10
10
  import { SmtpStatusCodes } from "../../smtp/client/SmtpStatusCodes.js";
11
- import TempFileService from "../../storage/TempFileService.js";
12
11
  import MailDispatcherService from "./MailDispatcherService.js";
13
12
  import EmailLogService from "../../services/email-logs/EmailLogService.js";
14
13
  import EmailAddressService from "../../services/EmailAddressService.js";
15
14
  // import PostReceiveWorkflow from "../post-receive/PostReceiveWorkflow.js";
16
15
  import ESmtpClient from "../../../protocols/smtp/ESmtpClient.js";
17
- import DnsService from "../../smtp/dns/DnsService.js";
18
16
  import EncryptionService from "../../services/encryption/EncryptionService.js";
19
17
  import EmailReferenceService from "../../smtp/services/EmailReferenceService.js";
20
18
  import EmailPostReceiveService from "../../smtp/services/EmailPostReceiveService.js";
21
- import EngagementService from "../../smtp/services/EngagementService.js";
22
19
  import TagService from "../../services/tags/TagService.js";
20
+ import { IMessageEnvelope } from "./IMessageEnvelope.js";
23
21
 
24
22
  export const smtpPool = new NamedObjectPool<SMTPClient>((host) => ({
25
23
  asyncFactory: () => new SMTPClient({ host }).connect(),
@@ -32,21 +30,6 @@ export const smtpPool = new NamedObjectPool<SMTPClient>((host) => ({
32
30
  },
33
31
  }));
34
32
 
35
- interface IMessageEnvelope {
36
- emailID: number;
37
- recipientAddressID: number;
38
- host: string;
39
- from: string;
40
- to: string[];
41
- modifyTo?: boolean;
42
- external: boolean;
43
- senderID?: number;
44
- activityID?: number;
45
- accessCode?: string;
46
- doNotSendDR?: boolean;
47
- listID?: number;
48
- }
49
-
50
33
  export default class DispatchEmailToMX extends Workflow<IMessageEnvelope> {
51
34
 
52
35
  private response: ISmtpResponse;
@@ -92,8 +75,7 @@ export default class DispatchEmailToMX extends Workflow<IMessageEnvelope> {
92
75
  async signEmail(
93
76
  @Inject mds?: MailDispatcherService
94
77
  ) {
95
- const { emailID, senderID, activityID, recipientAddressID, accessCode, external, to, listID, from } = this.input;
96
- return await mds.encodeForBulk({ emailID, senderID, activityID, recipientAddressID , accessCode, external, to, listID, from });
78
+ return await mds.encodeForBulk(this.input);
97
79
  }
98
80
 
99
81
  @UniqueActivity
@@ -310,6 +292,12 @@ export default class DispatchEmailToMX extends Workflow<IMessageEnvelope> {
310
292
  ) {
311
293
  const { emailID, recipientAddressID: emailAddressID, activityID } = this.input;
312
294
  db.verifyFilters = false;
295
+
296
+ if (this.signedFileLogID && this.input.saveHeadersOnly) {
297
+ // delete the log file...
298
+ await els.delete(this.signedFileLogID);
299
+ }
300
+
313
301
  if (this.response?.statusCode === SmtpStatusCodes.Ok) {
314
302
 
315
303
  await db.emailRecipients.statements.update({
@@ -320,9 +308,16 @@ export default class DispatchEmailToMX extends Workflow<IMessageEnvelope> {
320
308
  });
321
309
  await els.saveText(emailID,this.input.to.join(","), this.response.logs);
322
310
 
311
+ if (activityID) {
312
+ await db.subscriberActivities.statements.update({ activity: "sent" }, { activityID});
313
+ }
323
314
  return;
324
315
  }
325
316
 
317
+ if (activityID) {
318
+ await db.subscriberActivities.statements.update({ activity: "sent-failed" }, { activityID});
319
+ }
320
+
326
321
  db.raiseEvents = true;
327
322
 
328
323
  const now = DateTime.now;
@@ -0,0 +1,15 @@
1
+ export interface IMessageEnvelope {
2
+ emailID: number;
3
+ recipientAddressID: number;
4
+ host: string;
5
+ from: string;
6
+ to: string[];
7
+ modifyTo?: boolean;
8
+ external: boolean;
9
+ senderID?: number;
10
+ activityID?: number;
11
+ accessCode?: string;
12
+ doNotSendDR?: boolean;
13
+ saveHeadersOnly?: boolean;
14
+ listID?: number;
15
+ }
@@ -16,6 +16,7 @@ import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
16
16
  import { randomUUID } from "node:crypto";
17
17
  import DomainKeyService from "../../services/domain-keys/DomainKeyService.js";
18
18
  import EncryptionService from "../../services/encryption/EncryptionService.js";
19
+ import { IMessageEnvelope } from "./IMessageEnvelope.js";
19
20
 
20
21
  @RegisterScoped
21
22
  export default class MailDispatcherService {
@@ -41,8 +42,8 @@ export default class MailDispatcherService {
41
42
  @Inject
42
43
  encryptionService: EncryptionService;
43
44
 
44
- async encodeForBulk({ senderID, emailID, recipientAddressID, activityID, accessCode, external, to, listID, from }:
45
- { senderID: number, emailID: number, recipientAddressID: number, activityID: number, accessCode: string, external?: boolean, listID?: any, from: string, to: string[] }) {
45
+ async encodeForBulk({ senderID, emailID, recipientAddressID, activityID, accessCode, external, to, listID, from, saveHeadersOnly }:
46
+ IMessageEnvelope) {
46
47
  const { db, tfs, storage, htmlSanitizer } = this;
47
48
  db.verifyFilters = false;
48
49
  db.raiseEvents = false;
@@ -169,15 +170,17 @@ export default class MailDispatcherService {
169
170
  const log = await this.emailLogService.save(emailID, mailFile);
170
171
  return log.logID;
171
172
  }
172
- const signed = await this.signFile({ emailID, senderID, file: mailFile});
173
+ const signed = await this.signFile({ emailID, senderID, file: mailFile, saveHeadersOnly, recipientID: to[0]});
173
174
  return signed;
174
175
  }
175
176
 
176
177
  async signFile({
177
178
  emailID,
178
179
  senderID,
179
- file
180
- }: { emailID: number, senderID, file: LocalFile } ) {
180
+ file,
181
+ recipientID,
182
+ saveHeadersOnly
183
+ }: { emailID: number, recipientID, senderID, file: LocalFile, saveHeadersOnly?: boolean } ) {
181
184
  const { tfs } = this;
182
185
 
183
186
  const dks = ServiceProvider.resolve(this, DomainKeyService);
@@ -189,9 +192,22 @@ export default class MailDispatcherService {
189
192
  privateKey: dk.privateKey
190
193
  });
191
194
 
192
- const mailFile = await tfs.createFrom(`${emailID}.eml`, signer.sign( file.openReadStream()), "message/rfc822");
195
+ const mailFile = await tfs.createFrom(`${emailID}-${recipientID}.eml`, signer.sign( file.openReadStream()), "message/rfc822");
193
196
 
194
197
  const log = await this.emailLogService.save(emailID, mailFile);
198
+
199
+ if (saveHeadersOnly) {
200
+ // save a copy...
201
+ const headers = await tfs.createTempFile(".log", `${emailID}-${recipientID}.headers.log`, "message/rfc822");
202
+ for await(const line of mailFile.lines()) {
203
+ if (!line) {
204
+ break;
205
+ }
206
+ await headers.appendLine(line);
207
+ await this.emailLogService.save(emailID, headers);
208
+ }
209
+ }
210
+
195
211
  return log.logID;
196
212
  }
197
213
 
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=BroadcastEmailToMX.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BroadcastEmailToMX.d.ts","sourceRoot":"","sources":["../../../../src/server/workflows/channel/BroadcastEmailToMX.ts"],"names":[],"mappings":""}
@@ -1,219 +0,0 @@
1
- // import Inject from "@entity-access/entity-access/dist/di/di.js";
2
- // import Workflow, { UniqueActivity } from "@entity-access/entity-access/dist/workflows/Workflow.js";
3
- // import TempFileService from "../../storage/TempFileService.js";
4
- // import TimeSpan from "@entity-access/entity-access/dist/types/TimeSpan.js";
5
- // import { SmtpStatusCodes } from "../../smtp/client/SmtpStatusCodes.js";
6
- // import { ISmtpResponse } from "../../smtp/client/SMTPClient.js";
7
- // import SocialMailContext from "../../model/SocialMailContext.js";
8
- // import SubscriberActivity from "../../model/entities/SubscriberActivity.js";
9
- // import AppFile from "../../model/entities/AppFile.js";
10
- // import { Attachment } from "nodemailer/lib/mailer/index.js";
11
- // import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
12
- // import DKIM from "nodemailer/lib/dkim/index.js";
13
- // import MailComposer from "nodemailer/lib/mail-composer/index.js";
14
- // import { expandPlaceholders } from "../../services/TemplateExpander.js";
15
- // import HtmlSanitizer from "../../services/dom/HtmlSanitizer.js";
16
- // import sleep from "../../../common/sleep.js";
17
- // import { Base36 } from "../../../common/Base36.js";
18
- // import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
19
- // import Tracer from "../../../Tracer.js";
20
- // import EngagementService from "../../smtp/services/EngagementService.js";
21
- // import { smtpPool } from "../smtp/DispatchEmailToMX.js";
22
- // import EmailLogService from "../../services/email-logs/EmailLogService.js";
23
- export {};
24
- // export default class BroadcastEmailToMX extends Workflow<SubscriberActivity> {
25
- // private response: ISmtpResponse;
26
- // async run() {
27
- // let ts = TimeSpan.fromSeconds(60);
28
- // for (let index = 0; index < 5; index++) {
29
- // const status = this.response = await this.sendMail(index);
30
- // switch(status.statusCode) {
31
- // case SmtpStatusCodes.Ok:
32
- // await this.saveStatus();
33
- // return null;
34
- // case SmtpStatusCodes.ExceededStorageAllocation:
35
- // case SmtpStatusCodes.MailboxBusy:
36
- // case SmtpStatusCodes.TransactionFailed:
37
- // case SmtpStatusCodes.ServiceNotAvailable:
38
- // break;
39
- // default:
40
- // await this.saveStatus();
41
- // return status.status;
42
- // }
43
- // await this.delay(ts);
44
- // ts = ts.add(ts);
45
- // }
46
- // await this.saveStatus();
47
- // return "Failed after multiple attempts";
48
- // }
49
- // @UniqueActivity
50
- // async sendMail(
51
- // attempt: number,
52
- // @Inject db?: SocialMailContext,
53
- // @Inject tfs?: TempFileService,
54
- // @Inject es?: EngagementService,
55
- // @Inject htmlSanitizer?: HtmlSanitizer
56
- // ) {
57
- // const { activityID, emailID } = this.input;
58
- // db.verifyFilters = false;
59
- // db.raiseEvents = false;
60
- // const activity = await db.subscriberActivities
61
- // .where(this.input, (p) => (x) => x.activityID === p.activityID)
62
- // .include((x) => [
63
- // x.email.attachments,
64
- // x.email.senderEmail,
65
- // x.subscriber.mailbox,
66
- // x.subscriber.domain,
67
- // x.mailbox.emailAddress,
68
- // x.mailbox.domain.domainKeys
69
- // ])
70
- // .first();
71
- // const uid = activity.activityID;
72
- // const email = activity.email;
73
- // const to = activity.subscriber.emailAddress;
74
- // const headers = JSON.parse(email.headers ?? "{}");
75
- // let { inReplyTo } = headers;
76
- // if (email.parent) {
77
- // inReplyTo = `<${email.parent.headerMessageID}>`;
78
- // }
79
- // if (inReplyTo) {
80
- // if (!inReplyTo.startsWith("<")) {
81
- // inReplyTo = `<${inReplyTo}>`;
82
- // }
83
- // }
84
- // const senderEmail = activity.mailbox.emailAddress.emailAddress;
85
- // let html = email.htmlBody;
86
- // const s = htmlSanitizer.sanitize(html, email.textBody, {
87
- // senderEmail,
88
- // uid: Base36.encode(uid),
89
- // emailID: Base36.encode(emailID),
90
- // messageID: email.headerMessageID,
91
- // activityID: Base36.encode(activityID) as any,
92
- // });
93
- // html = s.html;
94
- // const senderName = activity.mailbox.emailAddress.name || activity.mailbox.name;
95
- // const now = DateTime.now;
96
- // if (!email.senderName) {
97
- // email.senderName = senderName;
98
- // }
99
- // const toAttachment = async (ea: AppFile): Promise<Attachment> => {
100
- // const tf = await tfs.downloadAppFile(ea);
101
- // return {
102
- // content: tf.openReadStream(),
103
- // filename: ea.name,
104
- // contentType: ea.contentType,
105
- // contentDisposition: ea.contentDisposition as any,
106
- // cid: ea.appFileID.toString()
107
- // };
108
- // };
109
- // const attachments = await Promise.all((email.attachments ?? []).map(toAttachment));
110
- // // prepare transport...
111
- // const mail = new MailComposer({
112
- // from: {
113
- // name: senderName,
114
- // address: senderEmail
115
- // },
116
- // to,
117
- // html,
118
- // text: email.textBody,
119
- // subject: email.subject,
120
- // messageId: email.headerMessageID,
121
- // inReplyTo,
122
- // attachments,
123
- // date: now.asJSDate,
124
- // headers: {
125
- // "Original-From": `"${senderName}" <${senderEmail}>`,
126
- // "List-Unsubscribe": `<mailto:unsubscribe-${senderEmail}>`
127
- // }
128
- // });
129
- // const mime = mail.compile();
130
- // const dk = activity.mailbox.domain.domainKeys[0];
131
- // const signer = new DKIM({
132
- // domainName: activity.mailbox.emailAddress.emailAddress.split("@").pop() ,
133
- // keySelector: dk.name,
134
- // privateKey: dk.privateKey
135
- // });
136
- // const mailFile = await tfs.createFrom(`${email.emailID}.eml`, signer.sign( mime.createReadStream()), "message/rfc822");
137
- // if (activity.subscriber.mailbox) {
138
- // const originalFile = db.appFiles.add({
139
- // name: "mail.eml",
140
- // contentType: mailFile.contentType,
141
- // file: mailFile
142
- // });
143
- // // we need to insert a copy into database...
144
- // // with recipient
145
- // db.emails.add({
146
- // originalFile,
147
- // textBody: s.text,
148
- // // htmlBody: s.html,
149
- // subject: email.subject,
150
- // senderID: activity.mailboxID,
151
- // headerMessageID: email.headerMessageID,
152
- // senderName: email.senderName || senderName,
153
- // recipients: [db.emailRecipients.add({
154
- // emailAddressID: activity.emailAddressID,
155
- // type: "to"
156
- // })],
157
- // attachments: email.attachments?.map((x) => db.appFiles.add({
158
- // ... x,
159
- // appFileID: void 0
160
- // })),
161
- // status: "received",
162
- // received: true,
163
- // dateSent: now,
164
- // dateReceived: now,
165
- // dateCreated: now,
166
- // mailboxes: [
167
- // db.mailboxEmails.add({
168
- // mailboxID: activity.emailAddressID
169
- // })
170
- // ]
171
- // });
172
- // db.raiseEvents = true;
173
- // db.verifyFilters = false;
174
- // await db.saveChanges();
175
- // return {
176
- // statusCode: SmtpStatusCodes.Ok,
177
- // logs: "Delivered"
178
- // } as ISmtpResponse;
179
- // }
180
- // const host = activity.subscriber.domain.name;
181
- // await using client = await smtpPool.acquire(host);
182
- // const status = await client.send({
183
- // from: senderEmail,
184
- // to: [to],
185
- // host
186
- // }, mailFile);
187
- // if (Number(status.statusCode) >= 400) {
188
- // Tracer.instance.error(status.logs, {
189
- // path: to,
190
- // host
191
- // });
192
- // }
193
- // return status;
194
- // }
195
- // @UniqueActivity
196
- // async saveStatus(
197
- // @Inject db?: SocialMailContext,
198
- // @Inject els?: EmailLogService
199
- // ) {
200
- // const { emailID, emailAddressID: subscriberID, mailboxID } = this.input;
201
- // db.verifyFilters = false;
202
- // const activity = this.response?.statusCode === SmtpStatusCodes.Ok
203
- // ? "sent"
204
- // : "failed";
205
- // await db.subscriberActivities.saveDirect({
206
- // mode: "insert",
207
- // changes: {
208
- // mailboxID,
209
- // emailID,
210
- // emailAddressID: subscriberID,
211
- // activity,
212
- // dateCreated: DateTime.now
213
- // }
214
- // });
215
- // await els.saveText(this.input.emailID, this.input.activityID.toString(), this.response.logs);
216
- // return;
217
- // }
218
- // }
219
- //# sourceMappingURL=BroadcastEmailToMX.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BroadcastEmailToMX.js","sourceRoot":"","sources":["../../../../src/server/workflows/channel/BroadcastEmailToMX.ts"],"names":[],"mappings":"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"}