async def _generate_message_entities(
        self,
        client: httpx.AsyncClient,
        folder_entity: OutlookMailFolderEntity,
        folder_breadcrumb: Breadcrumb,
    ) -> AsyncGenerator[ChunkEntity, None]:
        """Generate OutlookMessageEntity objects and their attachments for a given folder."""
        # Skip folders with no messages
        if folder_entity.total_item_count == 0:
            logger.debug(f"Skipping folder {folder_entity.display_name} - no messages")
            return

        logger.info(
            f"Starting message generation for folder: {folder_entity.display_name} "
            f"({folder_entity.total_item_count} items)"
        )

        url = f"{self.GRAPH_BASE_URL}/me/mailFolders/{folder_entity.entity_id}/messages"
        params = {"$top": 50}  # Fetch 50 messages at a time

        page_count = 0
        message_count = 0

        try:
            while url:
                page_count += 1
                logger.info(
                    f"Fetching message list page #{page_count} for folder "
                    f"{folder_entity.display_name}"
                )
                data = await self._get_with_auth(client, url, params=params)
                messages = data.get("value", [])
                logger.info(
                    f"Found {len(messages)} messages on page {page_count} in folder "
                    f"{folder_entity.display_name}"
                )

                for msg_idx, message_data in enumerate(messages):
                    message_count += 1
                    message_id = message_data.get("id", "unknown")
                    logger.debug(
                        f"Processing message #{msg_idx + 1}/{len(messages)} (ID: {message_id}) "
                        f"in folder {folder_entity.display_name}"
                    )

                    # If message doesn't have full data, fetch it
                    if "body" not in message_data:
                        logger.debug(f"Fetching full message details for {message_id}")
                        message_url = f"{self.GRAPH_BASE_URL}/me/messages/{message_id}"
                        message_data = await self._get_with_auth(client, message_url)

                    # Process the message
                    try:
                        async for entity in self._process_message(
                            client, message_data, folder_entity.display_name, folder_breadcrumb
                        ):
                            yield entity
                    except Exception as e:
                        logger.error(f"Error processing message {message_id}: {str(e)}")
                        # Continue with other messages even if one fails

                # Handle pagination
                url = data.get("@odata.nextLink")
                if url:
                    logger.debug("Following pagination to next page")
                    params = None  # params are included in the nextLink
                else:
                    logger.info(
                        f"Completed folder {folder_entity.display_name}. "
                        f"Processed {message_count} messages in {page_count} pages."
                    )
                    break

        except Exception as e:
            logger.error(
                f"Error processing messages in folder {folder_entity.display_name}: {str(e)}"
            )
            raise
Generate OutlookMessageEntity objects and their attachments for a given folder.
backend/airweave/platform/sources/outlook_mail.py