@social-mail/social-mail-web-server 1.4.921 → 1.4.923

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 (63) hide show
  1. package/dist/common/spawnPromise.js +1 -1
  2. package/dist/common/spawnPromise.js.map +1 -1
  3. package/dist/server/model/SocialMailContext.d.ts +2 -0
  4. package/dist/server/model/SocialMailContext.d.ts.map +1 -1
  5. package/dist/server/model/SocialMailContext.js +2 -0
  6. package/dist/server/model/SocialMailContext.js.map +1 -1
  7. package/dist/server/model/entities/Mailbox.d.ts +2 -0
  8. package/dist/server/model/entities/Mailbox.d.ts.map +1 -1
  9. package/dist/server/model/entities/Mailbox.js.map +1 -1
  10. package/dist/server/model/entities/MailboxContact.d.ts +3 -0
  11. package/dist/server/model/entities/MailboxContact.d.ts.map +1 -1
  12. package/dist/server/model/entities/MailboxContact.js +14 -1
  13. package/dist/server/model/entities/MailboxContact.js.map +1 -1
  14. package/dist/server/model/entities/MailboxFolder.d.ts +10 -0
  15. package/dist/server/model/entities/MailboxFolder.d.ts.map +1 -0
  16. package/dist/server/model/entities/MailboxFolder.js +47 -0
  17. package/dist/server/model/entities/MailboxFolder.js.map +1 -0
  18. package/dist/server/model/entities/Tag.d.ts +2 -0
  19. package/dist/server/model/entities/Tag.d.ts.map +1 -1
  20. package/dist/server/model/entities/Tag.js.map +1 -1
  21. package/dist/server/model/events/MailboxContactEvents.d.ts.map +1 -1
  22. package/dist/server/model/events/MailboxContactEvents.js +51 -0
  23. package/dist/server/model/events/MailboxContactEvents.js.map +1 -1
  24. package/dist/server/seed/tags/seed-tags.d.ts.map +1 -1
  25. package/dist/server/seed/tags/seed-tags.js +12 -0
  26. package/dist/server/seed/tags/seed-tags.js.map +1 -1
  27. package/dist/server/services/captcha/CaptchaService.d.ts.map +1 -1
  28. package/dist/server/services/captcha/CaptchaService.js +4 -2
  29. package/dist/server/services/captcha/CaptchaService.js.map +1 -1
  30. package/dist/server/services/tags/TagService.d.ts +3 -0
  31. package/dist/server/services/tags/TagService.d.ts.map +1 -1
  32. package/dist/server/services/tags/TagService.js +20 -0
  33. package/dist/server/services/tags/TagService.js.map +1 -1
  34. package/dist/server/smtp/services/EmailReferenceService.d.ts.map +1 -1
  35. package/dist/server/smtp/services/EmailReferenceService.js +39 -0
  36. package/dist/server/smtp/services/EmailReferenceService.js.map +1 -1
  37. package/dist/server/smtp/services/EmailSerializerService.d.ts +1 -0
  38. package/dist/server/smtp/services/EmailSerializerService.d.ts.map +1 -1
  39. package/dist/server/smtp/services/EmailSerializerService.js +2 -2
  40. package/dist/server/smtp/services/EmailSerializerService.js.map +1 -1
  41. package/dist/server/workflows/repair/mailbox-folders/RepairMailboxFoldersWorkflow.d.ts +11 -0
  42. package/dist/server/workflows/repair/mailbox-folders/RepairMailboxFoldersWorkflow.d.ts.map +1 -0
  43. package/dist/server/workflows/repair/mailbox-folders/RepairMailboxFoldersWorkflow.js +82 -0
  44. package/dist/server/workflows/repair/mailbox-folders/RepairMailboxFoldersWorkflow.js.map +1 -0
  45. package/dist/server/workflows/sync/SyncMailboxWorkflow.d.ts.map +1 -1
  46. package/dist/server/workflows/sync/SyncMailboxWorkflow.js +1 -0
  47. package/dist/server/workflows/sync/SyncMailboxWorkflow.js.map +1 -1
  48. package/dist/tsconfig.tsbuildinfo +1 -1
  49. package/package.json +1 -1
  50. package/src/common/spawnPromise.ts +1 -1
  51. package/src/server/model/SocialMailContext.ts +3 -0
  52. package/src/server/model/entities/Mailbox.ts +2 -0
  53. package/src/server/model/entities/MailboxContact.ts +11 -1
  54. package/src/server/model/entities/MailboxFolder.ts +37 -0
  55. package/src/server/model/entities/Tag.ts +2 -0
  56. package/src/server/model/events/MailboxContactEvents.ts +60 -0
  57. package/src/server/seed/tags/seed-tags.ts +18 -1
  58. package/src/server/services/captcha/CaptchaService.ts +4 -2
  59. package/src/server/services/tags/TagService.ts +23 -0
  60. package/src/server/smtp/services/EmailReferenceService.ts +44 -0
  61. package/src/server/smtp/services/EmailSerializerService.ts +7 -3
  62. package/src/server/workflows/repair/mailbox-folders/RepairMailboxFoldersWorkflow.ts +77 -0
  63. package/src/server/workflows/sync/SyncMailboxWorkflow.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@social-mail/social-mail-web-server",
3
- "version": "1.4.921",
3
+ "version": "1.4.923",
4
4
  "description": "## Phase 1",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -24,7 +24,7 @@ export const spawnPromise = (path, args?: string[], options?: SpawnOptionsWithou
24
24
  cd.on("error", (error) => {
25
25
  const errorText = color.red(error.stack ?? error.toString());
26
26
  all.push(error.stack ?? error.toString());
27
- if (logData) {
27
+ if (logData || logError) {
28
28
  console.error(errorText);
29
29
  }
30
30
  reject(error);
@@ -43,6 +43,7 @@ import AccessToken from "./entities/AccessToken.js";
43
43
  import ServerActivity from "./entities/ServerActivity.js";
44
44
  import IncomingSmsSource from "./entities/IncomingSmsSource.js";
45
45
  import VerificationToken, { VerificationTokenAddress } from "./entities/VerificationToken.js";
46
+ import MailboxFolder from "./entities/MailboxFolder.js";
46
47
 
47
48
  @RegisterScoped
48
49
  export default class SocialMailContext extends EntityContext {
@@ -107,6 +108,8 @@ export default class SocialMailContext extends EntityContext {
107
108
 
108
109
  public mailboxContacts = this.model.register(MailboxContact);
109
110
 
111
+ public mailboxFolders = this.model.register(MailboxFolder);
112
+
110
113
  public mailboxContactEmails = this.model.register(MailboxContactEmail);
111
114
 
112
115
  public mailboxContactTags = this.model.register(MailboxContactTag);
@@ -19,6 +19,7 @@ import { IgnoreJsonProperty, JsonProperty, ReadOnlyJsonProperty } from "@entity-
19
19
  import type ChannelConfig from "./ChannelConfig.js";
20
20
  import type { WebSiteChannel } from "./WebSiteFolder.js";
21
21
  import Domain from "./Domain.js";
22
+ import type MailboxFolder from "./MailboxFolder.js";
22
23
 
23
24
  /**
24
25
  * MailBox ID is number because foreign key on Email will
@@ -206,6 +207,7 @@ export default class Mailbox {
206
207
  public subscriberActivities: SubscriberActivity[];
207
208
 
208
209
  public websiteChannels: WebSiteChannel[];
210
+ folders: MailboxFolder[];
209
211
 
210
212
 
211
213
  }
@@ -25,9 +25,10 @@ export type subscriberStatusType = typeof subscriberStatus[number];
25
25
 
26
26
  @Table("MailboxContacts")
27
27
  @Index({
28
- name: "IX_MailBox_Thread_DateUpdated",
28
+ name: "IX_MailBox_Thread_Tagged_DateUpdated",
29
29
  columns: [
30
30
  { name: (x) => x.mailboxID, descending: false },
31
+ { name: (x) => x.folderTagID, descending: false },
31
32
  { name: (x) => x.dateUpdated, descending: true }
32
33
  ]
33
34
  })
@@ -59,6 +60,9 @@ export default class MailboxContact {
59
60
  })
60
61
  public emailAddressID: number;
61
62
 
63
+ @Column({ dataType: "BigInt", nullable: true })
64
+ public folderTagID: number;
65
+
62
66
  @Column({ dataType: "BigInt", nullable: true})
63
67
  @RelateTo(Email, {
64
68
  property: (mt) => mt.lastEmail,
@@ -118,6 +122,12 @@ export default class MailboxContact {
118
122
  @Column({ dataType: "Boolean", default: () => false})
119
123
  public blocked: boolean;
120
124
 
125
+ @Column({ dataType: "Boolean", default: () => false})
126
+ public newRequest: boolean;
127
+
128
+ @Column({ dataType: "Boolean", default: () => false})
129
+ public spam: boolean;
130
+
121
131
  @Column({ dataType: "Boolean", default: () => false})
122
132
  public mute: boolean;
123
133
 
@@ -0,0 +1,37 @@
1
+ import Column from "@entity-access/entity-access/dist/decorators/Column.js";
2
+ import { RelateTo } from "@entity-access/entity-access/dist/decorators/Relate.js";
3
+ import Table from "@entity-access/entity-access/dist/decorators/Table.js";
4
+ import Mailbox from "./Mailbox.js";
5
+ import Tag from "./Tag.js";
6
+
7
+ @Table("MailboxFolders")
8
+ export default class MailboxFolder {
9
+
10
+ @Column({ dataType: "BigInt", key: true })
11
+ @RelateTo(Mailbox, {
12
+ property: (x) => x.mailbox,
13
+ inverseProperty: (x) => x.folders,
14
+ foreignKeyConstraint: {
15
+ cascade: "delete"
16
+ }
17
+ })
18
+ mailboxID: number;
19
+
20
+ @Column({ dataType: "BigInt", key: true })
21
+ @RelateTo(Tag, {
22
+ property: (x) => x.tag,
23
+ inverseProperty: (x) => x.mailboxFolders,
24
+ foreignKeyConstraint: {
25
+ cascade: "restrict"
26
+ }
27
+ })
28
+ tagID: number;
29
+
30
+ @Column({ dataType: "Int", default: () => 0})
31
+ count: number;
32
+
33
+ mailbox: Mailbox;
34
+
35
+ tag: Tag;
36
+
37
+ }
@@ -9,6 +9,7 @@ import { IgnoreJsonProperty, ReadOnlyJsonProperty } from "@entity-access/server-
9
9
  import type MailboxContactTag from "./MailboxContactTag.js";
10
10
  import type EmailTag from "./EmailTag.js";
11
11
  import type { StoreItemFolderTag, StoreItemTag, StoreTag } from "./Store.js";
12
+ import type MailboxFolder from "./MailboxFolder.js";
12
13
 
13
14
  /**
14
15
  * The reason tags table exists in form of string,bigint pair is, we need
@@ -81,4 +82,5 @@ export default class Tag {
81
82
  public storeItemTags: StoreItemTag[];
82
83
  storeTags: StoreTag[];
83
84
  storeItemFolderTags: StoreItemFolderTag[];
85
+ mailboxFolders: MailboxFolder[];
84
86
  }
@@ -8,6 +8,8 @@ import { ForeignKeyFilter } from "@entity-access/entity-access/dist/model/events
8
8
  import SocialMailContext from "../SocialMailContext.js";
9
9
  import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
10
10
  import DateTime from "@entity-access/entity-access/dist/types/DateTime.js";
11
+ import EntityAccessError from "@entity-access/entity-access/dist/common/EntityAccessError.js";
12
+ import TagService from "../../services/tags/TagService.js";
11
13
 
12
14
  export default class MailboxContactEvents extends AuthenticatedEvents<MailboxContact> {
13
15
 
@@ -120,6 +122,64 @@ export default class MailboxContactEvents extends AuthenticatedEvents<MailboxCon
120
122
 
121
123
  }
122
124
 
125
+ let tagUpdated = false;
126
+
127
+ if (entry.isModified("folderTagID")) {
128
+ tagUpdated = true;
129
+ const oldID = entry.getChange("folderTagID").oldValue;
130
+ await db.mailboxFolders.where({ mailboxID, oldID }, (p) => (x) => x.mailboxID === p.mailboxID && x.tagID === p.oldID)
131
+ .update(void 0, (p) => (x) => ({
132
+ count: Sql.math.max(0, x.count-1)
133
+ }));
134
+ await db.mailboxFolders.where({ mailboxID, tagID: entity.folderTagID },
135
+ (p) => (x) => x.mailboxID === p.mailboxID && x.tagID === p.tagID)
136
+ .update(void 0, (p) => (x) => ({
137
+ count: x.count + 1
138
+ }));
139
+
140
+ const ts = ServiceProvider.resolve(this, TagService);
141
+ const spam = await ts.getSystemTagID("Spam");
142
+ const newRequest = await ts.getSystemTagID("New");
143
+ const isBlocked = await ts.getSystemTagID("Blocked");
144
+
145
+ entity.spam = spam === entity.folderTagID;
146
+ entity.newRequest = newRequest === entity.folderTagID;
147
+ entity.blocked = isBlocked === entity.folderTagID;
148
+ entry.detect();
149
+ }
150
+
151
+ if ( !tagUpdated && (entry.isModified("spam") || entry.isModified("newRequest") || entry.isModified("blocked"))) {
152
+ // update tag folder...
153
+ // only if older folder is one of the system folder...
154
+
155
+ const ts = ServiceProvider.resolve(this, TagService);
156
+ const systemIDs = await ts.getSystemTagIDs(["Contacts", "New", "Spam", "Blocked"]);
157
+ if (systemIDs.includes(entity.folderTagID)) {
158
+ const oldID = entity.folderTagID;
159
+ const tagID = await ts.getSystemTagID(entity.spam
160
+ ? "Spam"
161
+ : entity.newRequest
162
+ ? "New"
163
+ : entity.blocked
164
+ ? "Blocked"
165
+ : "Contacts");
166
+ entity.folderTagID = tagID;
167
+ if (tagID !== oldID) {
168
+ await db.mailboxFolders
169
+ .where({ mailboxID, oldID }, (p) =>
170
+ (x) => x.mailboxID === p.mailboxID && x.tagID === p.oldID)
171
+ .update(void 0, (p) => (x) => ({
172
+ count: Sql.math.max(0, x.count-1)
173
+ }));
174
+ await db.mailboxFolders
175
+ .where({ mailboxID, tagID }, (p) =>
176
+ (x) => x.mailboxID === p.mailboxID && x.tagID === p.tagID)
177
+ .update(void 0, (p) => (x) => ({
178
+ count: x.count + 1
179
+ }));
180
+ }
181
+ }
182
+ }
123
183
 
124
184
  if (entry.isModified("autoClose") || entry.isModified("blocked")) {
125
185
  if (autoClose || blocked) {
@@ -9,7 +9,7 @@ interface IFileTag {
9
9
 
10
10
  interface ITagParent {
11
11
  name: string;
12
- children: ITagLike[];
12
+ children?: ITagLike[];
13
13
  contentTypes?: string[];
14
14
  }
15
15
 
@@ -154,6 +154,23 @@ export default async function seedTags(context: SocialMailContext) {
154
154
  ]
155
155
  });
156
156
 
157
+ await addTag(context, {
158
+ name: "Contacts",
159
+ });
160
+
161
+ await addTag(context, {
162
+ name: "New",
163
+ });
164
+
165
+ await addTag(context, {
166
+ name: "Spam",
167
+ });
168
+
169
+ await addTag(context, {
170
+ name: "Blocked",
171
+ });
172
+
173
+
157
174
  await context.saveChanges();
158
175
 
159
176
  await updatePath(context);
@@ -94,7 +94,8 @@ export default class CaptchaService {
94
94
  "-map", "[v]",
95
95
  "-y", tf.path
96
96
  ], {
97
- logData: false
97
+ logData: false,
98
+ logCommand: false
98
99
  });
99
100
 
100
101
  await spawnPromise("/ffmpeg/ffmpeg", [
@@ -102,7 +103,8 @@ export default class CaptchaService {
102
103
  "-filter:v", "scale=300:-1",
103
104
  "-y", saveAs
104
105
  ],{
105
- logData: false
106
+ logData: false,
107
+ logCommand: false
106
108
  });
107
109
  }
108
110
 
@@ -2,10 +2,33 @@
2
2
  import { RegisterSingleton, ServiceProvider } from "@entity-access/entity-access/dist/di/di.js";
3
3
  import SocialMailContext from "../../model/SocialMailContext.js";
4
4
  import { ConsoleLogger } from "@entity-access/entity-access/dist/common/Logger.js";
5
+ import TimedCache from "@entity-access/entity-access/dist/common/cache/TimedCache.js";
6
+ import Tag from "../../model/entities/Tag.js";
5
7
 
6
8
  @RegisterSingleton
7
9
  export default class TagService {
8
10
 
11
+ map = new Map<string, number>();
12
+
13
+ async getSystemTagIDs(names: string[]) {
14
+ const ids = [];
15
+ for (const name of names) {
16
+ ids.push(await this.getSystemTagID(name));
17
+ }
18
+ return ids;
19
+ }
20
+
21
+ async getSystemTagID(name: string) {
22
+ name = name.trim().toLocaleLowerCase();
23
+ let tagID = this.map.get(name);
24
+ if (!tagID) {
25
+ const tags = await this.getTagID(name);
26
+ tagID = tags.pop();
27
+ this.map.set(name, tagID);
28
+ }
29
+ return tagID;
30
+ }
31
+
9
32
  async getTagID(name: string): Promise<number[]> {
10
33
  if (!name) {
11
34
  return [];
@@ -390,20 +390,50 @@ export default class EmailReferenceService {
390
390
  const unread = email.senderID === mailboxID || silent ? 0 : 1;
391
391
  const total = 1;
392
392
 
393
+ let newRequest = email.received && email.senderID !== mailboxID;
394
+
395
+ let blocked = false;
396
+ let spam = false;
397
+
398
+ let addFolder = true;
399
+
400
+ const name = spam
401
+ ? "Spam"
402
+ : blocked
403
+ ? "Blocked"
404
+ : newRequest
405
+ ? "New"
406
+ : "Contacts";
407
+
408
+ let tagID = await this.tagService.getSystemTagID(name);
409
+
393
410
  await db.mailboxContacts.statements.upsert({
394
411
  emailAddressID,
395
412
  mailboxID,
413
+ folderTagID: tagID,
396
414
  openThreads: newOpenThread === 1 ? 1 : 0,
397
415
  totalThreads: newThread === 1 ? 1 : 0,
398
416
  lastEmailID: emailID,
417
+ newRequest,
399
418
  dateUpdated,
419
+ blocked,
420
+ spam,
400
421
  unread,
401
422
  total
402
423
  },
403
424
  (item) => {
425
+ addFolder = false;
404
426
  item.unread = item.unread ? item.unread + ( unread ? 1 : 0 ) : 0;
405
427
  item.total = item.total ? item.total + 1 : 1;
406
428
  item.dateUpdated = dateUpdated;
429
+ newRequest = item.newRequest;
430
+ blocked = item.blocked;
431
+ spam = item.spam;
432
+ if(!item.folderTagID) {
433
+ item.folderTagID = tagID;
434
+ } else {
435
+ tagID = item.folderTagID;
436
+ }
407
437
  if (item.autoClose || item.blocked) {
408
438
  newOpenThread = 0;
409
439
  newThread = 0;
@@ -417,6 +447,20 @@ export default class EmailReferenceService {
417
447
  }
418
448
  );
419
449
 
450
+ if (addFolder) {
451
+ await db.mailboxFolders.statements.upsert({
452
+ mailboxID,
453
+ tagID,
454
+ count: 1
455
+ }, (x) => {
456
+ x.count++;
457
+ return x;
458
+ }, {
459
+ mailboxID,
460
+ tagID
461
+ });
462
+ }
463
+
420
464
 
421
465
  await db.mailboxes.where({ mailboxID }, (p) => (x) => x.mailboxID === p.mailboxID)
422
466
  .update({ newThread, newOpenThread, unread: unread ? 1 : 0 }, (p) => (x) => ({
@@ -105,7 +105,11 @@ const stripDuplicates = (addresses: IEmailRecipientInfo[]) => {
105
105
  };
106
106
 
107
107
  export interface IEmailInfo {
108
- externalEmailID: string, labels: string[], mailbox: Mailbox, silent?: boolean,
108
+ externalEmailID: string,
109
+ labels: string[],
110
+ mailbox: Mailbox,
111
+ silent?: boolean,
112
+ receivedViaSMTP?: boolean,
109
113
  messageId: string
110
114
  };
111
115
 
@@ -147,7 +151,7 @@ export default class EmailSerializerService {
147
151
  }
148
152
 
149
153
  async saveRFC822File(file: LocalFile, emailInfo: IEmailInfo) {
150
- const { externalEmailID, labels, mailbox, silent, messageId} = emailInfo;
154
+ const { externalEmailID, labels, mailbox, silent, messageId, receivedViaSMTP} = emailInfo;
151
155
  const { tempFileService, db } = this;
152
156
  // check if email already saved in same mailbox...
153
157
  const { mailboxID } = mailbox;
@@ -167,7 +171,7 @@ export default class EmailSerializerService {
167
171
  try {
168
172
  // scan for viruses....
169
173
  await AVService.scan(file);
170
- await this.save(file, { mailboxes, externalEmailID, silent, labels });
174
+ await this.save(file, { mailboxes, externalEmailID, silent, labels, received: receivedViaSMTP });
171
175
  } catch (error) {
172
176
  if (error instanceof FileInfectedError) {
173
177
 
@@ -0,0 +1,77 @@
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 SocialMailContext from "../../../model/SocialMailContext.js";
4
+ import Sql from "@entity-access/entity-access/dist/sql/Sql.js";
5
+ import Mailbox from "../../../model/entities/Mailbox.js";
6
+ import TagService from "../../../services/tags/TagService.js";
7
+
8
+ export default class RepairMailboxFoldersWorkflow extends Workflow {
9
+
10
+ static taskGroup = "batch";
11
+
12
+ async run() {
13
+ let start = 0;
14
+ do{
15
+ start = await this.fixEmailTags(start);
16
+ } while(BigInt(start));
17
+ }
18
+
19
+ @UniqueActivity
20
+ async fixEmailTags(
21
+ start: number,
22
+ @Inject db?: SocialMailContext,
23
+ @Inject ts?: TagService
24
+ ) {
25
+
26
+ const contacts = await ts.getSystemTagID("Contacts");
27
+ const isNew = await ts.getSystemTagID("New");
28
+ const isBlocked = await ts.getSystemTagID("Blocked");
29
+ const isSpam = await ts.getSystemTagID("Spam");
30
+
31
+ for(let i = 0;i< 100;i++) {
32
+ const mailboxes = await db.mailboxes.where({ start }, (p) => (x) => x.mailboxID > p.start)
33
+ .orderBy(void 0, (p) => (x) => x.mailboxID)
34
+ .limit(10)
35
+ .include((x) => [x.folders])
36
+ .toArray();
37
+
38
+ if (!mailboxes.length) {
39
+ return 0;
40
+ }
41
+
42
+ for (const iterator of mailboxes) {
43
+ start = iterator.mailboxID;
44
+ // fix tag...
45
+ const counts = await db.mailboxContacts.where(iterator, (p) => (x) => x.mailboxID === p.mailboxID)
46
+ .sum(void 0, (p) => (x) => ( {
47
+ blocked: x.blocked === true ? 1 : 0,
48
+ newRequest: x.newRequest === true ? 1 : 0,
49
+ spam: x.spam === true ? 1 : 0,
50
+ total: 1
51
+ }));
52
+
53
+ await this.saveFolder(db, iterator, contacts, counts.total);
54
+ await this.saveFolder(db, iterator, isNew, counts.total);
55
+ await this.saveFolder(db, iterator, isBlocked, counts.total);
56
+ await this.saveFolder(db, iterator, isSpam , counts.total);
57
+
58
+ }
59
+ db.changeSet.clear();
60
+ }
61
+ return start;
62
+ }
63
+
64
+ async saveFolder(db: SocialMailContext, { mailboxID }: Mailbox, tagID: number, count: number) {
65
+ await db.mailboxFolders.statements.upsert({
66
+ mailboxID,
67
+ tagID,
68
+ count
69
+ }, (x) => {
70
+ x.count = count;
71
+ return x;
72
+ }, {
73
+ mailboxID,
74
+ tagID
75
+ });
76
+ }
77
+ }
@@ -260,6 +260,7 @@ export default class SyncMailboxWorkflow extends Workflow<any, any> {
260
260
  messageId,
261
261
  labels,
262
262
  mailbox: target.mailbox,
263
+ receivedViaSMTP: false,
263
264
  silent: true
264
265
  });
265
266
  // console.log(`Saved ${uid}`);