@hyperbytes/wappler-imap-manager 1.0.5 → 1.0.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperbytes/wappler-imap-manager",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "IMAP eMail Management for Wappler",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -10,13 +10,17 @@
10
10
  "wappler-extension",
11
11
  "server-connect",
12
12
  "IMAP",
13
- "email"
13
+ "email",
14
+ "wappler",
15
+ "node"
14
16
  ],
15
17
  "dependencies": {
16
18
  "imap": "^0.8.0",
17
19
  "mailparser": "^3.7.2",
18
20
  "imap-simple": "^5.1.0",
19
21
  "mailtrap": "^4.1.0",
20
- "mailcomposer": "^1.0.0"
22
+ "mailcomposer": "^1.0.0",
23
+ "mime-types": "^3.0.1",
24
+ "mime-db": "^1.54.0"
21
25
  }
22
26
  }
@@ -10,23 +10,23 @@ groupIcon : 'fas fa-envelope comp-general',
10
10
  usedModules : {
11
11
  node: {
12
12
  'imap' : '^0.8.19',
13
- 'mailparser' : '^3.7.2'
13
+ 'mailparser' : '^3.7.2',
14
+ 'mime-lookup' : '^0.0.2',
15
+ 'mime-db' : '^1.54.0'
14
16
  }
15
17
  },
16
18
  dataScheme:[
17
- {name: 'savedFiles', type:'array', sub:[
18
- {name: '$value', type:'text'}
19
- ]},
20
- {name: 'message', type:'text'},
19
+ {name: 'status', type:'number'},
21
20
  {name: 'url', type:'text'},
22
21
  {name: 'path', type:'text'},
23
- {name: 'status', type:'text'},
24
- {name: 'pathschema', type:'array', sub:[
25
- {name: '$value', type:'text'}
22
+ {name: 'uploads', type:'file', sub:[
23
+ {name: 'name', type:'text'},
24
+ {name: 'path', type:'text'},
25
+ {name: 'url', type:'text'},
26
+ {name: 'type', type:'text'},
27
+ {name: 'size', type:'number'}
26
28
  ]},
27
- {name: 'systempath', type:'array', sub:[
28
- {name: '$value', type:'text'}
29
- ]}
29
+
30
30
  ],
31
31
 
32
32
 
@@ -3,6 +3,9 @@ const fs = require('fs');
3
3
  const { simpleParser } = require('mailparser');
4
4
  const path = require('path');
5
5
  const { toSystemPath } = require("../../../lib/core/path");
6
+ const mime = require('mime-types');
7
+ const mimeDb = require('mime-db');
8
+
6
9
 
7
10
  exports.imapgetattachments = async function (options, name) {
8
11
  const IMAP_USER = process.env.IMAP_USER;
@@ -15,8 +18,8 @@ exports.imapgetattachments = async function (options, name) {
15
18
  const mailbox = this.parseRequired(options.mailbox, '*', "No mailbox specified");
16
19
  let sentPath = this.parseRequired(options.path, '*', 'No path Specified');
17
20
  const returnPath = sentPath.split('/').slice(2).join('/');
18
- savePath = toSystemPath(sentPath);
19
-
21
+ //savePath = toSystemPath(sentPath);
22
+ savePath = sentPath;
20
23
  // Ensure the directory exists or create it
21
24
  if (!fs.existsSync(savePath)) {
22
25
  fs.mkdirSync(savePath, { recursive: true });
@@ -68,17 +71,39 @@ exports.imapgetattachments = async function (options, name) {
68
71
  console.log(`Saved attachment: ${filePath}`);
69
72
  });
70
73
  const savedFilesExt = [];
71
- const savedFilesSystem = []
74
+
72
75
  parsed.attachments.forEach(att => {
73
76
  const filePath = path.join(savePath, att.filename);
77
+ // Replace backslashes with forward slashes
78
+ let correctedPath = filePath.replace(/\\/g, "/");
79
+ // Remove the "public" prefix
80
+ correctedPathURL = correctedPath.replace(/^\/?public\//, "/");
81
+
82
+
74
83
  fs.writeFileSync(filePath, att.content);
75
- savedFilesExt.push(sentPath + att.filename);
76
- savedFilesSystem.push(toSystemPath(sentPath + att.filename));
77
- console.log(`Saved attachment Extemded: ${filePath}`);
84
+ let mimetype = mime.lookup(att.filename)
85
+ const fs2 = require('fs');
86
+
87
+ //const filePath = 'example.txt';
88
+ const stats = fs2.statSync(filePath);
89
+ console.log(`File size: ${stats.size} bytes`);
90
+ savedFilesExt.push({
91
+ name: att.filename,
92
+ path: correctedPath,
93
+ url: correctedPathURL,
94
+ type: mimetype,
95
+ size: stats.size
96
+
97
+ });
98
+
99
+ console.log(`Saved attachment Extended: ${filePath}`);
78
100
  });
79
101
 
102
+ // Output JSON
103
+ console.log(JSON.stringify(savedFilesExt, null, 2));
104
+
80
105
  imap.end();
81
- resolve({ savedFiles, message: savedFiles.join(", "), url: returnPath, path: sentPath, status: 200, pathschema: savedFilesExt, systemschema: savedFilesSystem });
106
+ resolve({ status: 200, url: returnPath, path: sentPath, uploads: savedFilesExt });
82
107
 
83
108
  } catch (parseError) {
84
109
  imap.end();
@@ -1,6 +1,7 @@
1
1
  const Imap = require('imap');
2
2
  const { simpleParser } = require('mailparser');
3
3
 
4
+
4
5
  exports.imapmailcontent = async function (options, name) {
5
6
  return new Promise((resolve, reject) => {
6
7
  const IMAP_USER = process.env.IMAP_USER;
@@ -0,0 +1,184 @@
1
+ const Imap = require('imap-simple');
2
+ const nodemailer = require('nodemailer');
3
+ const mailcomposer = require('mailcomposer');
4
+ const { simpleParser } = require('mailparser'); // Used for debugging email content
5
+
6
+ exports.imapsaveasdraft = async function (options) {
7
+ console.log('Starting IMAP draft save process...');
8
+
9
+ // Parse IMAP configuration
10
+ const IMAP_HOST = this.parseOptional(options.imap_host, '*', process.env.IMAP_HOST);
11
+ const IMAP_PASSWORD = this.parseOptional(options.imap_password, '*', process.env.IMAP_PASSWORD);
12
+ const IMAP_USER = this.parseOptional(options.imap_user, '*', process.env.IMAP_USER);
13
+ const IMAP_PORT = this.parseOptional(options.imap_port, '*', process.env.IMAP_PORT);
14
+ const imap_tlsstring = this.parseOptional(options.imap_tls, '*', process.env.IMAP_TLS).toLowerCase();
15
+ const IMAP_TLS = (imap_tlsstring === 'true');
16
+
17
+ // Validate essential IMAP configuration
18
+ if (!IMAP_HOST || !IMAP_USER || !IMAP_PASSWORD) {
19
+ console.error('IMAP host, user, or password not configured.');
20
+ return {
21
+ status: 401,
22
+ message: 'IMAP configuration incomplete.',
23
+ error: 'IMAP host, user, or password not configured.',
24
+ uid: '',
25
+ folder: this.parseOptional(options.mailbox, '*', 'Drafts')
26
+ };
27
+ }
28
+
29
+ // Parse email details
30
+ const to = this.parseOptional(options.to, "*", "");
31
+ console.log('To: ' + to);
32
+ const mailfrom = this.parseOptional(options.from, "*", "");
33
+ console.log('From: ' + mailfrom);
34
+ const cc = this.parseOptional(options.cc, "*", "");
35
+ console.log('CC: ' + cc);
36
+ const bcc = this.parseOptional(options.bcc, "*", "");
37
+ console.log('BCC: ' + bcc);
38
+ const subject = this.parseOptional(options.mailsubject, "*", "default subject");
39
+ console.log('Subject: ' + subject);
40
+ const body = this.parseOptional(options.body, "*", ""); // Assuming this is HTML body
41
+ console.log('Body: ' + body);
42
+ const attachments = this.parseOptional(options.attachments, '*', []);
43
+ console.log('Attachments: ' + attachments);
44
+ let folder = this.parseOptional(options.mailbox, '*', 'Drafts'); // Default to 'Drafts'
45
+ console.log('Folder: ' + folder);
46
+
47
+ // Check if a UID is provided – meaning the draft is to be updated
48
+ const providedUid = this.parseOptional(options.uid, "*", "");
49
+ console.log('UID: ' + providedUid);
50
+ console.log(`Attempting to save draft to folder: ${folder}`);
51
+
52
+ const imapConfig = {
53
+ imap: {
54
+ user: IMAP_USER,
55
+ password: IMAP_PASSWORD,
56
+ host: IMAP_HOST,
57
+ port: IMAP_PORT,
58
+ tls: IMAP_TLS,
59
+ tlsOptions: { rejectUnauthorized: false },
60
+ authTimeout: 5000
61
+ }
62
+ };
63
+
64
+ let connection;
65
+
66
+ try {
67
+ // 1. Construct the email message using mailcomposer
68
+ const mailOptions = {
69
+ from: mailfrom,
70
+ to: to,
71
+ cc: cc,
72
+ bcc: bcc,
73
+ subject: subject,
74
+ html: body, // Use 'text' if it's plain text
75
+ attachments: attachments
76
+ };
77
+
78
+ const mail = mailcomposer(mailOptions);
79
+
80
+ const rawEmail = await new Promise((resolve, reject) => {
81
+ mail.build((err, message) => {
82
+ if (err) {
83
+ console.error('Error building email:', err);
84
+ return {
85
+ status: 400,
86
+ message: 'Error building email.',
87
+ uid: '',
88
+ folder: folder
89
+ };
90
+ }
91
+ resolve(message);
92
+ });
93
+ });
94
+
95
+ console.log('Raw email constructed.');
96
+
97
+ // Debug: Parse the raw email to verify its content
98
+ const parsedEmail = await simpleParser(rawEmail);
99
+ console.log('Parsed Email Content:', {
100
+ subject: parsedEmail.subject,
101
+ text: parsedEmail.text,
102
+ html: parsedEmail.html,
103
+ headers: parsedEmail.headers
104
+ });
105
+
106
+ // 2. Connect to IMAP server
107
+ console.log(`Connecting to IMAP server ${IMAP_HOST}:${IMAP_PORT}...`);
108
+ connection = await Imap.connect(imapConfig);
109
+ console.log('Successfully connected to IMAP server.');
110
+
111
+ // 3. Open the target mailbox
112
+ await connection.openBox(folder);
113
+ console.log(`Mailbox "${folder}" opened.`);
114
+ // Retrieve UID validity of the destination mailbox (if available)
115
+
116
+
117
+ // 4. If a UID is provided, update the existing draft; otherwise, append a new one.
118
+ if (providedUid) {
119
+ console.log(`UID provided (${providedUid}). Updating existing draft...`);
120
+ // Attempt to delete the existing draft for that UID
121
+ try {
122
+ await connection.deleteMessage(providedUid);
123
+ console.log(`Existing draft with UID ${providedUid} deleted.`);
124
+ } catch (delErr) {
125
+ console.warn(`Could not delete existing draft with UID ${providedUid}: ${delErr}`);
126
+ // You might decide to abort here if deletion is mandatory
127
+ }
128
+ // Append the new draft (note: the server will normally assign a new UID,
129
+ // but we are returning the provided UID per the requirement).
130
+ console.log(`Appending updated draft to folder: ${folder}...`);
131
+ const updateAppendResult = await connection.append(rawEmail, {
132
+ mailbox: folder,
133
+ flags: ['\\Draft']
134
+ });
135
+ console.log('Updated draft appended.', updateAppendResult);
136
+
137
+ return {
138
+ status: 200,
139
+ message: 'Draft updated successfully.',
140
+ uid: providedUid,
141
+ folder: folder
142
+ };
143
+ } else {
144
+ console.log(`Appending email as a draft to folder: ${folder}...`);
145
+ const appendResult = await connection.append(rawEmail, {
146
+ mailbox: folder,
147
+ flags: ['\\Draft']
148
+ });
149
+ console.log('Email appended to drafts folder.', appendResult);
150
+
151
+ // Retrieve UID of the saved message
152
+ const searchResult = await connection.search(['ALL'], { bodies: ['HEADER.FIELDS (MESSAGE-ID)'] });
153
+ const uid = searchResult.length > 0 ? searchResult[searchResult.length - 1].attributes.uid : '';
154
+
155
+ return {
156
+ status: 200,
157
+ message: 'Draft saved successfully.',
158
+ uid: uid,
159
+ folder: folder
160
+ };
161
+ }
162
+
163
+ } catch (err) {
164
+ console.error('IMAP draft save failed:', err);
165
+ return {
166
+ status: 400,
167
+ message: 'Failed to save draft.',
168
+ error: err.toString(),
169
+ uid: '',
170
+ folder: folder
171
+ };
172
+ } finally {
173
+ if (connection) {
174
+ try {
175
+ await connection.end();
176
+ console.log('IMAP connection closed.');
177
+ } catch (endErr) {
178
+ console.error('Error ending IMAP connection:', endErr);
179
+ }
180
+ }
181
+ }
182
+ };
183
+
184
+
@@ -11,7 +11,9 @@
11
11
  node: {
12
12
  'imap' : '^0.8.19',
13
13
  'mailparser' : '^3.7.2',
14
- 'nodemailer' : '^6.10.1'
14
+ 'nodemailer' : '^6.10.1',
15
+ 'mime-lookup' : '^0.0.2',
16
+ 'mime-db' : '^1.54.0'
15
17
  }
16
18
  },
17
19
  dataScheme: [
@@ -164,11 +166,11 @@
164
166
  },
165
167
  { name: 'attachments',
166
168
  optionName: 'attachments',
167
- title: 'The eMail attachments',
169
+ title: 'eMail attachments sent from client',
168
170
  type: 'text',
169
171
  defaultValue: "",
170
172
  serverDataBindings: true,
171
- help: 'The email attachments'
173
+ help: 'eMail attachments sent from client via upload action'
172
174
  },
173
175
  { name: 'save_to_send',
174
176
  optionName: 'save_to_send',
@@ -6,7 +6,13 @@ const path = require("path");
6
6
  const { toSystemPath } = require("../../../lib/core/path");
7
7
 
8
8
  exports.imapsendmail = async function (options) {
9
- const upload = this.parseOptional(options.attachments, '*', '');
9
+ const upload = this.parseOptional(options.attachments, '*', []);
10
+ console.log("Attachments: " + JSON.stringify(upload))
11
+ const upload2 = this.parseOptional(options.server_attachments, '*', []);
12
+ console.log("Server_Attachments: " + JSON.stringify(upload2))
13
+ const combinedJson = { "attachments": [upload, upload2] };
14
+ console.log('CombinedJson: ' + JSON.stringify(combinedJson))
15
+
10
16
 
11
17
  // Ensure attachments are properly formatted and converted to system paths
12
18
  const attachmentList = Array.isArray(upload)
@@ -58,8 +64,8 @@ exports.imapsendmail = async function (options) {
58
64
  user: smtpConfig.username,
59
65
  pass: smtpConfig.password,
60
66
  },
61
- logger: true, // Enable logging
62
- debug: true, // Enable debugging
67
+ logger: false, // Enable logging
68
+ debug: false, // Enable debugging
63
69
 
64
70
  });
65
71
 
@@ -77,7 +83,9 @@ exports.imapsendmail = async function (options) {
77
83
  subject: subject,
78
84
  text: body,
79
85
  html: body,
80
- attachments: formattedAttachments,
86
+ attachments: formattedAttachments
87
+
88
+
81
89
  };
82
90
 
83
91
  console.log("Final Attachments List:", formattedAttachments);