-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgmailService.js
More file actions
106 lines (92 loc) · 4.08 KB
/
gmailService.js
File metadata and controls
106 lines (92 loc) · 4.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// src/services/gmailService.js
export class GmailService {
constructor(gmailClient) {
this.gmail = gmailClient;
}
/**
* Lista mensajes con filtros personalizados de Gmail.
* @param {Object} options - Opciones de filtrado.
* @param {String} [options.filter] - Filtro simple ('unread', 'promotions', 'attachments', 'old').
* @param {String} [options.dateBefore] - Fecha límite para correos viejos, formato YYYY/MM/DD.
* @param {Number} [options.maxResults] - Máximo de resultados.
* @param {Array} [options.combine] - Combinación de filtros.
* @returns {Promise<Array>} Lista de metadatos de mensajes.
*/
async listMessages({ filter, dateBefore, maxResults, combine }) {
const query = this._buildQuery({ filter, dateBefore, combine });
const res = await this.gmail.users.messages.list({
userId: 'me',
q: query,
maxResults: maxResults || 20,
});
const messages = res.data.messages || [];
return this._fetchMetadataForMessages(messages);
}
async listMessagesByQuery({ query, maxResults, pageToken }) {
const res = await this.gmail.users.messages.list({
userId: 'me',
q: query || '',
pageToken,
maxResults: maxResults || 20,
});
const messages = res.data.messages || [];
const emails = await this._fetchMetadataForMessages(messages);
return {
emails,
nextPageToken: res.data.nextPageToken || null,
total: res.data.resultSizeEstimate || 0,
};
}
_buildQuery({ filter, dateBefore, combine }) {
let queries = [];
const combined = combine || [];
if (filter) combined.push(filter);
if (combined.includes('unread')) queries.push('is:unread');
if (combined.includes('promotions')) queries.push('category:promotions');
if (combined.includes('attachments')) queries.push('has:attachment larger:2M');
if (combined.includes('old'))
queries.push(`before:${dateBefore ? dateBefore.replace(/-/g, '/') : '2023/01/01'}`);
return queries.join(' ') || '';
}
async _fetchMetadataForMessages(messages) {
// Trae solo metadatos de cada mensaje (id, subject, from, date, snippet, adjunto, size)
const results = [];
for (const msg of messages) {
const msgData = await this.gmail.users.messages.get({
userId: 'me',
id: msg.id,
format: 'metadata',
metadataHeaders: ['Subject', 'From', 'Date'],
});
const payload = msgData.data.payload || {};
const headers = (payload.headers || []).reduce((acc, h) => {
acc[h.name.toLowerCase()] = h.value;
return acc;
}, {});
function detectCategoryFromLabels(labels) {
if (labels.includes('CATEGORY_PROMOTIONS')) return 'promotions';
if (labels.includes('CATEGORY_SOCIAL')) return 'social';
if (labels.includes('CATEGORY_UPDATES')) return 'updates';
if (labels.includes('CATEGORY_FORUMS')) return 'forums';
if (labels.includes('INBOX')) return 'primary';
return undefined;
}
results.push({
id: msg.id,
subject: headers.subject || '',
from: headers.from || '',
date: headers.date || '',
labels: msgData.data.labelIds || [],
isRead: !(msgData.data.labelIds?.includes('UNREAD')),
category: detectCategoryFromLabels(msgData.data.labelIds || []) || 'unknown',
attachmentSizeMb: msgData.data.sizeEstimate
? msgData.data.sizeEstimate / (1024 * 1024)
: 0,
snippet: msgData.data.snippet,
hasAttachment: (payload.parts || []).some(part => part.filename && part.filename !== ''),
size: msgData.data.sizeEstimate,
});
}
return results;
}
}