( accessToken: string, config: OutlookWebhookConfig, requestId: string, logger: Logger )
| 180 | const OUTLOOK_PAGE_SIZE = 50 |
| 181 | |
| 182 | async function fetchNewOutlookEmails( |
| 183 | accessToken: string, |
| 184 | config: OutlookWebhookConfig, |
| 185 | requestId: string, |
| 186 | logger: Logger |
| 187 | ) { |
| 188 | try { |
| 189 | const apiUrl = 'https://graph.microsoft.com/v1.0/me/messages' |
| 190 | const params = new URLSearchParams() |
| 191 | |
| 192 | params.append( |
| 193 | '$select', |
| 194 | 'id,conversationId,subject,bodyPreview,body,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,hasAttachments,isRead,parentFolderId' |
| 195 | ) |
| 196 | params.append('$orderby', 'receivedDateTime desc') |
| 197 | const maxEmails = Math.min(config.maxEmailsPerPoll || 25, OUTLOOK_HARD_MAX_EMAILS) |
| 198 | params.append('$top', OUTLOOK_PAGE_SIZE.toString()) |
| 199 | |
| 200 | if (config.lastCheckedTimestamp) { |
| 201 | const lastChecked = new Date(config.lastCheckedTimestamp) |
| 202 | const bufferTime = new Date(lastChecked.getTime() - 60000) |
| 203 | params.append('$filter', `receivedDateTime gt ${bufferTime.toISOString()}`) |
| 204 | } |
| 205 | const allEmails: OutlookEmail[] = [] |
| 206 | let nextUrl: string | undefined = `${apiUrl}?${params.toString()}` |
| 207 | logger.info(`[${requestId}] Fetching emails from: ${nextUrl}`) |
| 208 | |
| 209 | while (nextUrl && allEmails.length < maxEmails) { |
| 210 | const response = await fetchWithRetry(nextUrl, { |
| 211 | headers: { |
| 212 | Authorization: `Bearer ${accessToken}`, |
| 213 | }, |
| 214 | }) |
| 215 | |
| 216 | if (!response.ok) { |
| 217 | const errorData = await response |
| 218 | .json() |
| 219 | .catch(() => ({ error: { message: 'Unknown error' } })) |
| 220 | logger.error(`[${requestId}] Microsoft Graph API error:`, { |
| 221 | status: response.status, |
| 222 | statusText: response.statusText, |
| 223 | error: errorData, |
| 224 | }) |
| 225 | throw new Error( |
| 226 | `Microsoft Graph API error: ${response.status} ${response.statusText} - ${JSON.stringify(errorData)}` |
| 227 | ) |
| 228 | } |
| 229 | |
| 230 | const data = await response.json() |
| 231 | const pageEmails: OutlookEmail[] = data.value || [] |
| 232 | const remaining = maxEmails - allEmails.length |
| 233 | allEmails.push(...pageEmails.slice(0, remaining)) |
| 234 | |
| 235 | nextUrl = |
| 236 | allEmails.length < maxEmails ? (data['@odata.nextLink'] as string | undefined) : undefined |
| 237 | |
| 238 | if (pageEmails.length === 0) break |
| 239 | } |
no test coverage detected