@@ -359,7 +359,19 @@ async function fetchNewOutlookEmails(
359359 const data = await response . json ( )
360360 const emails = data . value || [ ]
361361
362- const filteredEmails = filterEmailsByFolder ( emails , config )
362+ let resolvedFolderIds : Map < string , string > | undefined
363+ if ( config . folderIds && config . folderIds . length > 0 ) {
364+ const hasWellKnownFolders = config . folderIds . some ( isWellKnownFolderName )
365+ if ( hasWellKnownFolders ) {
366+ resolvedFolderIds = await resolveWellKnownFolderIds (
367+ accessToken ,
368+ config . folderIds ,
369+ requestId
370+ )
371+ }
372+ }
373+
374+ const filteredEmails = filterEmailsByFolder ( emails , config , resolvedFolderIds )
363375
364376 logger . info (
365377 `[${ requestId } ] Fetched ${ emails . length } emails, ${ filteredEmails . length } after filtering`
@@ -373,18 +385,103 @@ async function fetchNewOutlookEmails(
373385 }
374386}
375387
388+ const OUTLOOK_WELL_KNOWN_FOLDERS = new Set ( [
389+ 'inbox' ,
390+ 'drafts' ,
391+ 'sentitems' ,
392+ 'deleteditems' ,
393+ 'junkemail' ,
394+ 'archive' ,
395+ 'outbox' ,
396+ ] )
397+
398+ function isWellKnownFolderName ( folderId : string ) : boolean {
399+ return OUTLOOK_WELL_KNOWN_FOLDERS . has ( folderId . toLowerCase ( ) )
400+ }
401+
402+ async function resolveWellKnownFolderId (
403+ accessToken : string ,
404+ folderName : string ,
405+ requestId : string
406+ ) : Promise < string | null > {
407+ try {
408+ const response = await fetch ( `https://graph.microsoft.com/v1.0/me/mailFolders/${ folderName } ` , {
409+ headers : {
410+ Authorization : `Bearer ${ accessToken } ` ,
411+ 'Content-Type' : 'application/json' ,
412+ } ,
413+ } )
414+
415+ if ( ! response . ok ) {
416+ logger . warn (
417+ `[${ requestId } ] Failed to resolve well-known folder '${ folderName } ': ${ response . status } `
418+ )
419+ return null
420+ }
421+
422+ const folder = await response . json ( )
423+ return folder . id || null
424+ } catch ( error ) {
425+ logger . error ( `[${ requestId } ] Error resolving well-known folder '${ folderName } ':` , error )
426+ return null
427+ }
428+ }
429+
430+ async function resolveWellKnownFolderIds (
431+ accessToken : string ,
432+ folderIds : string [ ] ,
433+ requestId : string
434+ ) : Promise < Map < string , string > > {
435+ const resolvedIds = new Map < string , string > ( )
436+
437+ const wellKnownFolders = folderIds . filter ( isWellKnownFolderName )
438+ if ( wellKnownFolders . length === 0 ) {
439+ return resolvedIds
440+ }
441+
442+ const resolutions = await Promise . all (
443+ wellKnownFolders . map ( async ( folderName ) => {
444+ const actualId = await resolveWellKnownFolderId ( accessToken , folderName , requestId )
445+ return { folderName, actualId }
446+ } )
447+ )
448+
449+ for ( const { folderName, actualId } of resolutions ) {
450+ if ( actualId ) {
451+ resolvedIds . set ( folderName . toLowerCase ( ) , actualId )
452+ }
453+ }
454+
455+ logger . info (
456+ `[${ requestId } ] Resolved ${ resolvedIds . size } /${ wellKnownFolders . length } well-known folders`
457+ )
458+
459+ return resolvedIds
460+ }
461+
376462function filterEmailsByFolder (
377463 emails : OutlookEmail [ ] ,
378- config : OutlookWebhookConfig
464+ config : OutlookWebhookConfig ,
465+ resolvedFolderIds ?: Map < string , string >
379466) : OutlookEmail [ ] {
380467 if ( ! config . folderIds || ! config . folderIds . length ) {
381468 return emails
382469 }
383470
471+ const actualFolderIds = config . folderIds . map ( ( configFolder ) => {
472+ if ( resolvedFolderIds && isWellKnownFolderName ( configFolder ) ) {
473+ const resolvedId = resolvedFolderIds . get ( configFolder . toLowerCase ( ) )
474+ if ( resolvedId ) {
475+ return resolvedId
476+ }
477+ }
478+ return configFolder
479+ } )
480+
384481 return emails . filter ( ( email ) => {
385482 const emailFolderId = email . parentFolderId
386- const hasMatchingFolder = config . folderIds ! . some ( ( configFolder ) =>
387- emailFolderId . toLowerCase ( ) . includes ( configFolder . toLowerCase ( ) )
483+ const hasMatchingFolder = actualFolderIds . some (
484+ ( folderId ) => emailFolderId . toLowerCase ( ) === folderId . toLowerCase ( )
388485 )
389486
390487 return config . folderFilterBehavior === 'INCLUDE' ? hasMatchingFolder : ! hasMatchingFolder
0 commit comments