@cli4ai/gmail 1.0.3 → 1.0.5
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/README.md +75 -75
- package/{c4ai.json → cli4ai.json} +1 -1
- package/package.json +9 -13
- package/lib/api.test.ts +0 -287
- package/lib/api.ts +0 -299
- package/lib/attachments.ts +0 -199
- package/lib/drafts.ts +0 -434
- package/lib/labels.ts +0 -198
- package/lib/messages.ts +0 -310
- package/lib/send.ts +0 -331
- package/lib/threads.ts +0 -164
package/lib/messages.ts
DELETED
|
@@ -1,310 +0,0 @@
|
|
|
1
|
-
import { getGmail, output, formatDate, extractHeaders, extractBody, cleanBody, type OutputOptions, type MessagePayload } from './api';
|
|
2
|
-
|
|
3
|
-
/** Message summary */
|
|
4
|
-
export interface MessageSummary {
|
|
5
|
-
id: string;
|
|
6
|
-
threadId?: string;
|
|
7
|
-
date: string | null;
|
|
8
|
-
from: string;
|
|
9
|
-
to: string;
|
|
10
|
-
subject: string;
|
|
11
|
-
snippet?: string;
|
|
12
|
-
labels?: string[];
|
|
13
|
-
unread?: boolean;
|
|
14
|
-
starred?: boolean;
|
|
15
|
-
important?: boolean;
|
|
16
|
-
body?: string;
|
|
17
|
-
cc?: string | null;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/** Action result */
|
|
21
|
-
export interface ActionResult {
|
|
22
|
-
ok: boolean;
|
|
23
|
-
archived?: string;
|
|
24
|
-
trashed?: string;
|
|
25
|
-
untrashed?: string;
|
|
26
|
-
starred?: string;
|
|
27
|
-
unstarred?: string;
|
|
28
|
-
markedRead?: string;
|
|
29
|
-
markedUnread?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Message list options */
|
|
33
|
-
export interface MessageListOptions extends OutputOptions {
|
|
34
|
-
limit?: number;
|
|
35
|
-
body?: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* List inbox messages
|
|
40
|
-
*/
|
|
41
|
-
export async function inbox(options: MessageListOptions = {}): Promise<MessageSummary[]> {
|
|
42
|
-
const gmail = await getGmail();
|
|
43
|
-
const limit = options.limit || 20;
|
|
44
|
-
|
|
45
|
-
const res = await gmail.users.messages.list({
|
|
46
|
-
userId: 'me',
|
|
47
|
-
maxResults: limit,
|
|
48
|
-
labelIds: ['INBOX']
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
if (!res.data.messages || res.data.messages.length === 0) {
|
|
52
|
-
output([], options);
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const messages = await Promise.all(
|
|
57
|
-
res.data.messages.map(msg => getMessageSummary(gmail, msg.id!, options))
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
output(messages, options);
|
|
61
|
-
return messages;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* List unread messages
|
|
66
|
-
*/
|
|
67
|
-
export async function unread(options: MessageListOptions = {}): Promise<MessageSummary[]> {
|
|
68
|
-
const gmail = await getGmail();
|
|
69
|
-
const limit = options.limit || 20;
|
|
70
|
-
|
|
71
|
-
const res = await gmail.users.messages.list({
|
|
72
|
-
userId: 'me',
|
|
73
|
-
maxResults: limit,
|
|
74
|
-
q: 'is:unread'
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
if (!res.data.messages || res.data.messages.length === 0) {
|
|
78
|
-
output([], options);
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const messages = await Promise.all(
|
|
83
|
-
res.data.messages.map(msg => getMessageSummary(gmail, msg.id!, options))
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
output(messages, options);
|
|
87
|
-
return messages;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Search messages with Gmail query syntax
|
|
92
|
-
*/
|
|
93
|
-
export async function search(query: string, options: MessageListOptions = {}): Promise<MessageSummary[]> {
|
|
94
|
-
const gmail = await getGmail();
|
|
95
|
-
const limit = options.limit || 20;
|
|
96
|
-
|
|
97
|
-
const res = await gmail.users.messages.list({
|
|
98
|
-
userId: 'me',
|
|
99
|
-
maxResults: limit,
|
|
100
|
-
q: query
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
if (!res.data.messages || res.data.messages.length === 0) {
|
|
104
|
-
output([], options);
|
|
105
|
-
return [];
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const messages = await Promise.all(
|
|
109
|
-
res.data.messages.map(msg => getMessageSummary(gmail, msg.id!, options))
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
output(messages, options);
|
|
113
|
-
return messages;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Get message summary (for list views)
|
|
118
|
-
*/
|
|
119
|
-
async function getMessageSummary(gmail: ReturnType<typeof import('googleapis').google.gmail>, messageId: string, options: MessageListOptions = {}): Promise<MessageSummary> {
|
|
120
|
-
const res = await gmail.users.messages.get({
|
|
121
|
-
userId: 'me',
|
|
122
|
-
id: messageId,
|
|
123
|
-
format: options.body ? 'full' : 'metadata',
|
|
124
|
-
metadataHeaders: ['From', 'To', 'Subject', 'Date']
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const headers = extractHeaders(res.data.payload?.headers as Array<{ name: string; value: string }>);
|
|
128
|
-
const labels = res.data.labelIds || [];
|
|
129
|
-
|
|
130
|
-
const summary: MessageSummary = {
|
|
131
|
-
id: res.data.id!,
|
|
132
|
-
threadId: res.data.threadId || undefined,
|
|
133
|
-
date: formatDate(res.data.internalDate),
|
|
134
|
-
from: headers.from || '',
|
|
135
|
-
to: headers.to || '',
|
|
136
|
-
subject: headers.subject || '(no subject)',
|
|
137
|
-
snippet: res.data.snippet || '',
|
|
138
|
-
labels: labels,
|
|
139
|
-
unread: labels.includes('UNREAD'),
|
|
140
|
-
starred: labels.includes('STARRED'),
|
|
141
|
-
important: labels.includes('IMPORTANT')
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
if (options.body) {
|
|
145
|
-
summary.body = cleanBody(extractBody(res.data.payload as MessagePayload), 1000);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
return summary;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Read a full message
|
|
153
|
-
*/
|
|
154
|
-
export async function read(messageId: string, options: OutputOptions = {}): Promise<MessageSummary> {
|
|
155
|
-
const gmail = await getGmail();
|
|
156
|
-
|
|
157
|
-
const res = await gmail.users.messages.get({
|
|
158
|
-
userId: 'me',
|
|
159
|
-
id: messageId,
|
|
160
|
-
format: 'full'
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
const headers = extractHeaders(res.data.payload?.headers as Array<{ name: string; value: string }>);
|
|
164
|
-
const labels = res.data.labelIds || [];
|
|
165
|
-
const body = extractBody(res.data.payload as MessagePayload);
|
|
166
|
-
|
|
167
|
-
const message: MessageSummary = {
|
|
168
|
-
id: res.data.id!,
|
|
169
|
-
threadId: res.data.threadId || undefined,
|
|
170
|
-
date: formatDate(res.data.internalDate),
|
|
171
|
-
from: headers.from || '',
|
|
172
|
-
to: headers.to || '',
|
|
173
|
-
cc: headers.cc || null,
|
|
174
|
-
subject: headers.subject || '(no subject)',
|
|
175
|
-
body: body,
|
|
176
|
-
labels: labels,
|
|
177
|
-
unread: labels.includes('UNREAD'),
|
|
178
|
-
starred: labels.includes('STARRED')
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
output(message, options);
|
|
182
|
-
return message;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Archive a message (remove from INBOX)
|
|
187
|
-
*/
|
|
188
|
-
export async function archive(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
189
|
-
const gmail = await getGmail();
|
|
190
|
-
|
|
191
|
-
await gmail.users.messages.modify({
|
|
192
|
-
userId: 'me',
|
|
193
|
-
id: messageId,
|
|
194
|
-
requestBody: {
|
|
195
|
-
removeLabelIds: ['INBOX']
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
const result: ActionResult = { ok: true, archived: messageId };
|
|
200
|
-
output(result, options);
|
|
201
|
-
return result;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Trash a message
|
|
206
|
-
*/
|
|
207
|
-
export async function trash(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
208
|
-
const gmail = await getGmail();
|
|
209
|
-
|
|
210
|
-
await gmail.users.messages.trash({
|
|
211
|
-
userId: 'me',
|
|
212
|
-
id: messageId
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
const result: ActionResult = { ok: true, trashed: messageId };
|
|
216
|
-
output(result, options);
|
|
217
|
-
return result;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Untrash a message
|
|
222
|
-
*/
|
|
223
|
-
export async function untrash(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
224
|
-
const gmail = await getGmail();
|
|
225
|
-
|
|
226
|
-
await gmail.users.messages.untrash({
|
|
227
|
-
userId: 'me',
|
|
228
|
-
id: messageId
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
const result: ActionResult = { ok: true, untrashed: messageId };
|
|
232
|
-
output(result, options);
|
|
233
|
-
return result;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Star a message
|
|
238
|
-
*/
|
|
239
|
-
export async function star(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
240
|
-
const gmail = await getGmail();
|
|
241
|
-
|
|
242
|
-
await gmail.users.messages.modify({
|
|
243
|
-
userId: 'me',
|
|
244
|
-
id: messageId,
|
|
245
|
-
requestBody: {
|
|
246
|
-
addLabelIds: ['STARRED']
|
|
247
|
-
}
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
const result: ActionResult = { ok: true, starred: messageId };
|
|
251
|
-
output(result, options);
|
|
252
|
-
return result;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/**
|
|
256
|
-
* Unstar a message
|
|
257
|
-
*/
|
|
258
|
-
export async function unstar(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
259
|
-
const gmail = await getGmail();
|
|
260
|
-
|
|
261
|
-
await gmail.users.messages.modify({
|
|
262
|
-
userId: 'me',
|
|
263
|
-
id: messageId,
|
|
264
|
-
requestBody: {
|
|
265
|
-
removeLabelIds: ['STARRED']
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
const result: ActionResult = { ok: true, unstarred: messageId };
|
|
270
|
-
output(result, options);
|
|
271
|
-
return result;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Mark as read
|
|
276
|
-
*/
|
|
277
|
-
export async function markRead(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
278
|
-
const gmail = await getGmail();
|
|
279
|
-
|
|
280
|
-
await gmail.users.messages.modify({
|
|
281
|
-
userId: 'me',
|
|
282
|
-
id: messageId,
|
|
283
|
-
requestBody: {
|
|
284
|
-
removeLabelIds: ['UNREAD']
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
|
|
288
|
-
const result: ActionResult = { ok: true, markedRead: messageId };
|
|
289
|
-
output(result, options);
|
|
290
|
-
return result;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Mark as unread
|
|
295
|
-
*/
|
|
296
|
-
export async function markUnread(messageId: string, options: OutputOptions = {}): Promise<ActionResult> {
|
|
297
|
-
const gmail = await getGmail();
|
|
298
|
-
|
|
299
|
-
await gmail.users.messages.modify({
|
|
300
|
-
userId: 'me',
|
|
301
|
-
id: messageId,
|
|
302
|
-
requestBody: {
|
|
303
|
-
addLabelIds: ['UNREAD']
|
|
304
|
-
}
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
const result: ActionResult = { ok: true, markedUnread: messageId };
|
|
308
|
-
output(result, options);
|
|
309
|
-
return result;
|
|
310
|
-
}
|
package/lib/send.ts
DELETED
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import { getGmail, output, encodeBase64Url, extractHeaders, extractBody, type OutputOptions, type MessagePayload } from './api';
|
|
2
|
-
import { createMultipartMessage, createSimpleMessage } from './drafts';
|
|
3
|
-
|
|
4
|
-
/** Send result */
|
|
5
|
-
export interface SendResult {
|
|
6
|
-
ok: boolean;
|
|
7
|
-
id?: string;
|
|
8
|
-
threadId?: string;
|
|
9
|
-
to?: string;
|
|
10
|
-
subject?: string;
|
|
11
|
-
inReplyTo?: string;
|
|
12
|
-
forwardedFrom?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** Send options */
|
|
16
|
-
export interface SendOptions extends OutputOptions {
|
|
17
|
-
cc?: string;
|
|
18
|
-
bcc?: string;
|
|
19
|
-
attach?: string | string[];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Create raw email message
|
|
24
|
-
*/
|
|
25
|
-
function createRawMessage({ to, cc, bcc, subject, body, inReplyTo, references }: {
|
|
26
|
-
to: string;
|
|
27
|
-
cc?: string;
|
|
28
|
-
bcc?: string;
|
|
29
|
-
subject: string;
|
|
30
|
-
body: string;
|
|
31
|
-
inReplyTo?: string;
|
|
32
|
-
references?: string;
|
|
33
|
-
}): string {
|
|
34
|
-
const lines: string[] = [];
|
|
35
|
-
|
|
36
|
-
lines.push(`To: ${to}`);
|
|
37
|
-
if (cc) lines.push(`Cc: ${cc}`);
|
|
38
|
-
if (bcc) lines.push(`Bcc: ${bcc}`);
|
|
39
|
-
lines.push(`Subject: ${subject}`);
|
|
40
|
-
lines.push('Content-Type: text/plain; charset=utf-8');
|
|
41
|
-
|
|
42
|
-
if (inReplyTo) {
|
|
43
|
-
lines.push(`In-Reply-To: ${inReplyTo}`);
|
|
44
|
-
lines.push(`References: ${references || inReplyTo}`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
lines.push('');
|
|
48
|
-
lines.push(body);
|
|
49
|
-
|
|
50
|
-
return encodeBase64Url(lines.join('\r\n'));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Send a new email
|
|
55
|
-
*/
|
|
56
|
-
export async function send(to: string, subject: string, body: string, options: SendOptions = {}): Promise<SendResult> {
|
|
57
|
-
const gmail = await getGmail();
|
|
58
|
-
|
|
59
|
-
// Process newlines in body
|
|
60
|
-
body = body.replace(/\\n/g, '\n');
|
|
61
|
-
|
|
62
|
-
let raw: string;
|
|
63
|
-
if (options.attach) {
|
|
64
|
-
const attachments = Array.isArray(options.attach) ? options.attach : [options.attach];
|
|
65
|
-
const attachmentPaths = attachments.map(a => ({ path: a }));
|
|
66
|
-
raw = createMultipartMessage({
|
|
67
|
-
to,
|
|
68
|
-
cc: options.cc,
|
|
69
|
-
bcc: options.bcc,
|
|
70
|
-
subject,
|
|
71
|
-
body,
|
|
72
|
-
attachments: attachmentPaths
|
|
73
|
-
});
|
|
74
|
-
} else {
|
|
75
|
-
raw = createRawMessage({
|
|
76
|
-
to,
|
|
77
|
-
cc: options.cc,
|
|
78
|
-
bcc: options.bcc,
|
|
79
|
-
subject,
|
|
80
|
-
body
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const res = await gmail.users.messages.send({
|
|
85
|
-
userId: 'me',
|
|
86
|
-
requestBody: { raw }
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const result: SendResult = {
|
|
90
|
-
ok: true,
|
|
91
|
-
id: res.data.id || undefined,
|
|
92
|
-
threadId: res.data.threadId || undefined,
|
|
93
|
-
to,
|
|
94
|
-
subject
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
output(result, options);
|
|
98
|
-
return result;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Reply to a message
|
|
103
|
-
*/
|
|
104
|
-
export async function reply(messageId: string, body: string, options: SendOptions = {}): Promise<SendResult> {
|
|
105
|
-
const gmail = await getGmail();
|
|
106
|
-
|
|
107
|
-
// Get original message to extract headers
|
|
108
|
-
const original = await gmail.users.messages.get({
|
|
109
|
-
userId: 'me',
|
|
110
|
-
id: messageId,
|
|
111
|
-
format: 'metadata',
|
|
112
|
-
metadataHeaders: ['From', 'To', 'Subject', 'Message-ID', 'References']
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const headers = extractHeaders(original.data.payload?.headers as Array<{ name: string; value: string }>);
|
|
116
|
-
|
|
117
|
-
// Determine who to reply to
|
|
118
|
-
const replyTo = headers.from!;
|
|
119
|
-
let subject = headers.subject || '';
|
|
120
|
-
if (!subject.toLowerCase().startsWith('re:')) {
|
|
121
|
-
subject = `Re: ${subject}`;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Process newlines in body
|
|
125
|
-
body = body.replace(/\\n/g, '\n');
|
|
126
|
-
|
|
127
|
-
let raw: string;
|
|
128
|
-
if (options.attach) {
|
|
129
|
-
const attachments = Array.isArray(options.attach) ? options.attach : [options.attach];
|
|
130
|
-
const attachmentPaths = attachments.map(a => ({ path: a }));
|
|
131
|
-
raw = createMultipartMessage({
|
|
132
|
-
to: replyTo,
|
|
133
|
-
subject,
|
|
134
|
-
body,
|
|
135
|
-
inReplyTo: headers.message_id,
|
|
136
|
-
references: headers.references ? `${headers.references} ${headers.message_id}` : headers.message_id,
|
|
137
|
-
attachments: attachmentPaths
|
|
138
|
-
});
|
|
139
|
-
} else {
|
|
140
|
-
raw = createRawMessage({
|
|
141
|
-
to: replyTo,
|
|
142
|
-
subject,
|
|
143
|
-
body,
|
|
144
|
-
inReplyTo: headers.message_id,
|
|
145
|
-
references: headers.references ? `${headers.references} ${headers.message_id}` : headers.message_id
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const res = await gmail.users.messages.send({
|
|
150
|
-
userId: 'me',
|
|
151
|
-
requestBody: {
|
|
152
|
-
raw,
|
|
153
|
-
threadId: original.data.threadId || undefined
|
|
154
|
-
}
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
const result: SendResult = {
|
|
158
|
-
ok: true,
|
|
159
|
-
id: res.data.id || undefined,
|
|
160
|
-
threadId: res.data.threadId || undefined,
|
|
161
|
-
to: replyTo,
|
|
162
|
-
subject,
|
|
163
|
-
inReplyTo: messageId
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
output(result, options);
|
|
167
|
-
return result;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Reply all
|
|
172
|
-
*/
|
|
173
|
-
export async function replyAll(messageId: string, body: string, options: SendOptions = {}): Promise<SendResult> {
|
|
174
|
-
const gmail = await getGmail();
|
|
175
|
-
|
|
176
|
-
// Get original message
|
|
177
|
-
const original = await gmail.users.messages.get({
|
|
178
|
-
userId: 'me',
|
|
179
|
-
id: messageId,
|
|
180
|
-
format: 'metadata',
|
|
181
|
-
metadataHeaders: ['From', 'To', 'Cc', 'Subject', 'Message-ID', 'References']
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
const headers = extractHeaders(original.data.payload?.headers as Array<{ name: string; value: string }>);
|
|
185
|
-
|
|
186
|
-
// Get my email address
|
|
187
|
-
const profile = await gmail.users.getProfile({ userId: 'me' });
|
|
188
|
-
const myEmail = profile.data.emailAddress!;
|
|
189
|
-
|
|
190
|
-
// Build recipient list (original From + all To/Cc, excluding myself)
|
|
191
|
-
const allRecipients = new Set<string>();
|
|
192
|
-
allRecipients.add(headers.from!);
|
|
193
|
-
|
|
194
|
-
if (headers.to) {
|
|
195
|
-
headers.to.split(',').forEach(email => allRecipients.add(email.trim()));
|
|
196
|
-
}
|
|
197
|
-
if (headers.cc) {
|
|
198
|
-
headers.cc.split(',').forEach(email => allRecipients.add(email.trim()));
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
// Remove myself from recipients
|
|
202
|
-
const recipients = Array.from(allRecipients).filter(
|
|
203
|
-
email => !email.toLowerCase().includes(myEmail.toLowerCase())
|
|
204
|
-
);
|
|
205
|
-
|
|
206
|
-
let subject = headers.subject || '';
|
|
207
|
-
if (!subject.toLowerCase().startsWith('re:')) {
|
|
208
|
-
subject = `Re: ${subject}`;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
body = body.replace(/\\n/g, '\n');
|
|
212
|
-
|
|
213
|
-
const raw = createRawMessage({
|
|
214
|
-
to: recipients.join(', '),
|
|
215
|
-
subject,
|
|
216
|
-
body,
|
|
217
|
-
inReplyTo: headers.message_id,
|
|
218
|
-
references: headers.references ? `${headers.references} ${headers.message_id}` : headers.message_id
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
const res = await gmail.users.messages.send({
|
|
222
|
-
userId: 'me',
|
|
223
|
-
requestBody: {
|
|
224
|
-
raw,
|
|
225
|
-
threadId: original.data.threadId || undefined
|
|
226
|
-
}
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
const result: SendResult = {
|
|
230
|
-
ok: true,
|
|
231
|
-
id: res.data.id || undefined,
|
|
232
|
-
threadId: res.data.threadId || undefined,
|
|
233
|
-
to: recipients.join(', '),
|
|
234
|
-
subject,
|
|
235
|
-
inReplyTo: messageId
|
|
236
|
-
};
|
|
237
|
-
|
|
238
|
-
output(result, options);
|
|
239
|
-
return result;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
/**
|
|
243
|
-
* Forward a message
|
|
244
|
-
*/
|
|
245
|
-
export async function forward(messageId: string, to: string, body?: string, options: OutputOptions = {}): Promise<SendResult> {
|
|
246
|
-
const gmail = await getGmail();
|
|
247
|
-
|
|
248
|
-
// Get original message with full body
|
|
249
|
-
const original = await gmail.users.messages.get({
|
|
250
|
-
userId: 'me',
|
|
251
|
-
id: messageId,
|
|
252
|
-
format: 'full'
|
|
253
|
-
});
|
|
254
|
-
|
|
255
|
-
const headers = extractHeaders(original.data.payload?.headers as Array<{ name: string; value: string }>);
|
|
256
|
-
const originalBody = extractBody(original.data.payload as MessagePayload);
|
|
257
|
-
|
|
258
|
-
let subject = headers.subject || '';
|
|
259
|
-
if (!subject.toLowerCase().startsWith('fwd:')) {
|
|
260
|
-
subject = `Fwd: ${subject}`;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Build forwarded message body
|
|
264
|
-
const forwardedContent = [
|
|
265
|
-
body ? body.replace(/\\n/g, '\n') : '',
|
|
266
|
-
'',
|
|
267
|
-
'---------- Forwarded message ----------',
|
|
268
|
-
`From: ${headers.from}`,
|
|
269
|
-
`Date: ${headers.date}`,
|
|
270
|
-
`Subject: ${headers.subject}`,
|
|
271
|
-
`To: ${headers.to}`,
|
|
272
|
-
'',
|
|
273
|
-
originalBody
|
|
274
|
-
].join('\n');
|
|
275
|
-
|
|
276
|
-
const raw = createRawMessage({
|
|
277
|
-
to,
|
|
278
|
-
subject,
|
|
279
|
-
body: forwardedContent
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
const res = await gmail.users.messages.send({
|
|
283
|
-
userId: 'me',
|
|
284
|
-
requestBody: { raw }
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
const result: SendResult = {
|
|
288
|
-
ok: true,
|
|
289
|
-
id: res.data.id || undefined,
|
|
290
|
-
threadId: res.data.threadId || undefined,
|
|
291
|
-
to,
|
|
292
|
-
subject,
|
|
293
|
-
forwardedFrom: messageId
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
output(result, options);
|
|
297
|
-
return result;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Create draft
|
|
302
|
-
*/
|
|
303
|
-
export async function draft(to: string, subject: string, body: string, options: SendOptions = {}): Promise<SendResult> {
|
|
304
|
-
const gmail = await getGmail();
|
|
305
|
-
|
|
306
|
-
body = body.replace(/\\n/g, '\n');
|
|
307
|
-
|
|
308
|
-
const raw = createRawMessage({
|
|
309
|
-
to,
|
|
310
|
-
cc: options.cc,
|
|
311
|
-
subject,
|
|
312
|
-
body
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
const res = await gmail.users.drafts.create({
|
|
316
|
-
userId: 'me',
|
|
317
|
-
requestBody: {
|
|
318
|
-
message: { raw }
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
const result: SendResult = {
|
|
323
|
-
ok: true,
|
|
324
|
-
id: res.data.id || undefined,
|
|
325
|
-
to,
|
|
326
|
-
subject
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
output(result, options);
|
|
330
|
-
return result;
|
|
331
|
-
}
|