dooray-mail-cli 0.1.1 → 0.1.2

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/SKILL.md CHANGED
@@ -122,6 +122,30 @@ You'll be prompted for:
122
122
  - Subject: email subject
123
123
  - Body: email content (press Ctrl+D when done)
124
124
 
125
+ ### Reply to an Email
126
+
127
+ **Non-interactive (recommended for automation):**
128
+
129
+ ```bash
130
+ dooray-cli reply 123 --body "Thank you for your email."
131
+ ```
132
+
133
+ **Interactive mode:**
134
+
135
+ ```bash
136
+ dooray-cli reply 123
137
+ ```
138
+
139
+ **How it works:**
140
+ 1. First, read the email using `dooray-cli read <uid>`
141
+ 2. The email information (Message-ID, sender, subject) is cached automatically
142
+ 3. Use `reply <uid>` to send a reply
143
+ 4. The reply will:
144
+ - Automatically set recipient to original sender
145
+ - Add "Re:" prefix to subject (if not already present)
146
+ - Include proper email threading headers (In-Reply-To, References)
147
+ - Appear in the same conversation thread in email clients
148
+
125
149
  ### Search Emails
126
150
 
127
151
  Search for emails by keywords in subject:
@@ -232,7 +232,9 @@ class DoorayMailClient {
232
232
  html: params.html ? params.body : undefined,
233
233
  cc: params.cc?.join(', '),
234
234
  bcc: params.bcc?.join(', '),
235
- attachments: params.attachments
235
+ attachments: params.attachments,
236
+ inReplyTo: params.inReplyTo || undefined,
237
+ references: params.references || undefined
236
238
  };
237
239
  const info = await this.smtpTransporter.sendMail(mailOptions);
238
240
  console.log('[Dooray] Mail sent:', info.messageId);
@@ -320,6 +322,7 @@ class DoorayMailClient {
320
322
  const parsed = await (0, mailparser_1.simpleParser)(all.body);
321
323
  return {
322
324
  id: uid.toString(),
325
+ messageId: parsed.messageId || '',
323
326
  subject: parsed.subject || '(제목 없음)',
324
327
  from: {
325
328
  name: parsed.from?.value[0]?.name || parsed.from?.text || '알 수 없음',
@@ -333,7 +336,9 @@ class DoorayMailClient {
333
336
  bodyHtml: parsed.html || undefined,
334
337
  receivedAt: parsed.date?.toISOString() || new Date().toISOString(),
335
338
  isRead: flags.includes('\\Seen'),
336
- hasAttachments: (parsed.attachments?.length || 0) > 0
339
+ hasAttachments: (parsed.attachments?.length || 0) > 0,
340
+ inReplyTo: parsed.inReplyTo || '',
341
+ references: parsed.references || []
337
342
  };
338
343
  }
339
344
  catch (error) {
package/dooray-cli.js CHANGED
@@ -12,6 +12,7 @@ const path = require('path');
12
12
  const os = require('os');
13
13
 
14
14
  const CONFIG_PATH = path.join(os.homedir(), '.dooray-config.json');
15
+ const CACHE_PATH = path.join(os.homedir(), '.dooray-mail-cache.json');
15
16
 
16
17
  // CLI 명령어 파서
17
18
  const args = process.argv.slice(2);
@@ -31,6 +32,23 @@ function saveConfig(config) {
31
32
  fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
32
33
  }
33
34
 
35
+ // 메일 캐시 로드
36
+ function loadCache() {
37
+ if (!fs.existsSync(CACHE_PATH)) {
38
+ return {};
39
+ }
40
+ try {
41
+ return JSON.parse(fs.readFileSync(CACHE_PATH, 'utf-8'));
42
+ } catch {
43
+ return {};
44
+ }
45
+ }
46
+
47
+ // 메일 캐시 저장
48
+ function saveCache(cache) {
49
+ fs.writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2), 'utf-8');
50
+ }
51
+
34
52
  // 메일 클라이언트 생성
35
53
  async function createClient(config) {
36
54
  const security = new SecurityManager();
@@ -62,6 +80,9 @@ async function handleCommand() {
62
80
  case 'send':
63
81
  await sendCommand(args.slice(1));
64
82
  break;
83
+ case 'reply':
84
+ await replyCommand(args[1], args.slice(2));
85
+ break;
65
86
  case 'search':
66
87
  await searchCommand(args.slice(1));
67
88
  break;
@@ -184,12 +205,23 @@ async function readCommand(uid) {
184
205
  process.exit(1);
185
206
  }
186
207
 
208
+ // 메일 정보 캐시에 저장 (답장용)
209
+ const cache = loadCache();
210
+ cache[uid] = {
211
+ messageId: mail.messageId,
212
+ subject: mail.subject,
213
+ from: mail.from,
214
+ references: mail.references || []
215
+ };
216
+ saveCache(cache);
217
+
187
218
  const fromText = typeof mail.from === 'object' ? `${mail.from.name} <${mail.from.email}>` : mail.from;
188
219
  const toText = Array.isArray(mail.to)
189
220
  ? mail.to.map(t => typeof t === 'object' ? `${t.name} <${t.email}>` : t).join(', ')
190
221
  : mail.to;
191
222
 
192
223
  console.log('\n📧 Mail Details\n');
224
+ console.log(`UID: ${uid}`);
193
225
  console.log(`From: ${fromText}`);
194
226
  console.log(`To: ${toText}`);
195
227
  console.log(`Subject: ${mail.subject}`);
@@ -204,6 +236,84 @@ async function readCommand(uid) {
204
236
  }
205
237
  }
206
238
 
239
+ // reply: 답장 보내기
240
+ async function replyCommand(uid, args) {
241
+ if (!uid) {
242
+ console.error('❌ Usage: dooray-cli reply <uid> [--body "message"]');
243
+ process.exit(1);
244
+ }
245
+
246
+ // 캐시에서 원본 메일 정보 로드
247
+ const cache = loadCache();
248
+ const originalMail = cache[uid];
249
+
250
+ if (!originalMail) {
251
+ console.error('❌ Mail not found in cache. Please read the mail first using: dooray-cli read ' + uid);
252
+ process.exit(1);
253
+ }
254
+
255
+ // --body 옵션 파싱
256
+ let body;
257
+ for (let i = 0; i < args.length; i++) {
258
+ if (args[i] === '--body' && args[i + 1]) {
259
+ body = args[++i];
260
+ }
261
+ }
262
+
263
+ const config = loadConfig();
264
+ const client = await createClient(config);
265
+
266
+ try {
267
+ // 인터랙티브 모드
268
+ if (!body) {
269
+ const readline = require('readline').createInterface({
270
+ input: process.stdin,
271
+ output: process.stdout
272
+ });
273
+
274
+ console.log(`\n💬 Reply to: ${originalMail.from.name} <${originalMail.from.email}>`);
275
+ console.log(` Subject: Re: ${originalMail.subject}\n`);
276
+ console.log('Body (type message, press Ctrl+D when done):');
277
+
278
+ body = '';
279
+ readline.on('line', (line) => {
280
+ body += line + '\n';
281
+ });
282
+
283
+ await new Promise(resolve => readline.on('close', resolve));
284
+ }
285
+
286
+ // 답장 제목 생성
287
+ const replySubject = originalMail.subject.startsWith('Re:')
288
+ ? originalMail.subject
289
+ : `Re: ${originalMail.subject}`;
290
+
291
+ // References 헤더 생성
292
+ const references = [...(originalMail.references || [])];
293
+ if (originalMail.messageId && !references.includes(originalMail.messageId)) {
294
+ references.push(originalMail.messageId);
295
+ }
296
+
297
+ // 답장 발송
298
+ await client.sendMail({
299
+ to: originalMail.from.email,
300
+ subject: replySubject,
301
+ text: body.trim(),
302
+ inReplyTo: originalMail.messageId,
303
+ references: references.join(' ')
304
+ });
305
+
306
+ console.log('\n✅ Reply sent successfully');
307
+ console.log(` To: ${originalMail.from.name} <${originalMail.from.email}>`);
308
+ console.log(` Subject: ${replySubject}`);
309
+ } catch (error) {
310
+ console.error('❌ Error:', error.message);
311
+ process.exit(1);
312
+ } finally {
313
+ await client.close();
314
+ }
315
+ }
316
+
207
317
  // send: 메일 발송
208
318
  async function sendCommand(args) {
209
319
  // 비인터랙티브 모드: --to, --subject, --body 옵션 사용
@@ -353,6 +463,9 @@ Commands:
353
463
  send Send a new mail (interactive)
354
464
  send --to <email> --subject <subject> --body <body>
355
465
  Send a mail (non-interactive)
466
+ reply <uid> Reply to a mail (interactive)
467
+ reply <uid> --body <body>
468
+ Reply to a mail (non-interactive)
356
469
  search <keywords> Search mails by keywords
357
470
  unread Show unread mail count
358
471
  test Test IMAP/SMTP connection
@@ -364,6 +477,8 @@ Examples:
364
477
  dooray-cli recent
365
478
  dooray-cli read 123
366
479
  dooray-cli send --to "user@example.com" --subject "Hello" --body "Test message"
480
+ dooray-cli reply 123
481
+ dooray-cli reply 123 --body "Thank you for your email."
367
482
  dooray-cli search "meeting" "report"
368
483
  dooray-cli unread
369
484
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dooray-mail-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Dooray mail CLI for OpenClaw Skill - IMAP/SMTP integration",
5
5
  "main": "./dist/mail-client.js",
6
6
  "bin": {