Skip to content

Conversation

@joeyorlando
Copy link
Contributor

Summary

This PR adds comprehensive email attachment handling to the incoming email provider, enabling agents to receive and process file attachments from incoming emails through the Microsoft Graph API.

Key Changes

  • New Constants (constants.ts):

    • MAX_ATTACHMENT_SIZE: 10MB limit per individual attachment
    • MAX_TOTAL_ATTACHMENTS_SIZE: 25MB limit for all attachments per email (respects Microsoft Graph API limits)
    • MAX_ATTACHMENTS_PER_EMAIL: 20 attachment limit per email to prevent excessive processing
  • New Type (types/incoming-email.ts):

    • EmailAttachment interface with properties: id, name, contentType, size, contentBase64, isInline, contentId
    • Updated IncomingEmail interface to include optional attachments field
  • Provider Implementation (outlook-provider.ts):

    • New getAttachments() method that fetches attachment metadata and optionally content from Microsoft Graph API
    • Integrated attachment fetching into the email processing pipeline
    • Added hasAttachments field to message selection for efficient filtering
  • Comprehensive Test Coverage (outlook-provider.test.ts):

    • 10 new test cases covering: basic attachment fetching, metadata-only mode, size limit enforcement, total size limits, non-file attachment filtering, error handling, and edge cases

Implementation Details

  • Size Enforcement: Attachments exceeding individual or total size limits are gracefully skipped with appropriate logging
  • Attachment Type Filtering: Only file attachments are processed; item attachments (forwarded emails) and reference attachments (cloud files) are skipped
  • Error Resilience: If content fetch fails, metadata is still returned; if attachment fetch entirely fails, processing continues without attachments
  • Efficient API Usage: Metadata is fetched in a single call; content is only fetched when requested and per-attachment
  • Logging: Detailed debug and warning logs for attachment processing decisions

https://claude.ai/code/session_013gpmZvxDAu8mZdRS2Vpmb9

Adds the ability for agents to receive and process email attachments
when invoked through the incoming email feature:

- Add EmailAttachment interface with fields for id, name, contentType,
  size, contentBase64, isInline, and contentId
- Update IncomingEmail interface to include optional attachments array
- Add getAttachments method to AgentIncomingEmailProvider interface
- Implement attachment fetching in OutlookEmailProvider using
  Microsoft Graph API
- Update parseWebhookNotification to automatically fetch attachments
- Add size constraints: 10MB individual limit, 25MB total per message
- Add comprehensive tests for attachment functionality

https://claude.ai/code/session_013gpmZvxDAu8mZdRS2Vpmb9
Copilot AI review requested due to automatic review settings January 27, 2026 11:20
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@joeyorlando joeyorlando changed the title Add email attachment support to incoming email provider feat: email attachment support for agent incoming emails Jan 27, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive email attachment handling to the incoming email provider, enabling agents to receive and process file attachments from incoming emails through the Microsoft Graph API. The implementation includes size limits, attachment type filtering, and error resilience to ensure robust handling of email attachments.

Changes:

  • Added attachment-related constants for size limits and count restrictions
  • Extended type definitions to support email attachments with metadata and content
  • Implemented attachment fetching in the Outlook provider with comprehensive validation and error handling

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
platform/backend/src/types/incoming-email.ts Added EmailAttachment interface and extended IncomingEmail and provider interface to support attachments
platform/backend/src/agents/incoming-email/outlook-provider.ts Implemented getAttachments() method with size validation, type filtering, and integrated attachment fetching into email processing
platform/backend/src/agents/incoming-email/outlook-provider.test.ts Added 10 comprehensive test cases covering attachment fetching scenarios, edge cases, and error handling
platform/backend/src/agents/incoming-email/constants.ts Defined attachment size limits and count restrictions as constants
Comments suppressed due to low confidence (1)

platform/backend/src/agents/incoming-email/outlook-provider.ts:1

  • The test expects contentId to be undefined when the API returns null, but the implementation at line 962 directly assigns attachment.contentId without converting null to undefined. This will cause the test assertion to fail. Update line 962 to handle null values: contentId: attachment.contentId || undefined
import crypto from "node:crypto";


const emailAttachment: EmailAttachment = {
id: attachment.id,
name: attachment.name || "unnamed",
Copy link

Copilot AI Jan 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the fallback value 'unnamed' for missing attachment names could cause confusion when multiple attachments lack names. Consider using a more descriptive fallback like 'attachment-{id}' or 'untitled-attachment' to help distinguish between unnamed attachments.

Suggested change
name: attachment.name || "unnamed",
name:
attachment.name ||
(attachment.id ? `attachment-${attachment.id}` : "untitled-attachment"),

Copilot uses AI. Check for mistakes.
@claude
Copy link
Contributor

claude bot commented Jan 27, 2026

Claude finished @joeyorlando's task in 50s —— View job


Code Review: Email Attachment Support

  • Read repository guidelines (CLAUDE.md)
  • Review changed files
  • Analyze code quality, security, performance, and testing
  • Provide comprehensive review feedback

Overall, this is a well-implemented feature with good error handling and comprehensive test coverage. I found a few issues that should be addressed:


Issues Found

1. Bug: contentId: null vs undefined mismatch (outlook-provider.ts:962)

The test at line 713 expects contentId: undefined when the API returns null, but the implementation directly assigns attachment.contentId without conversion. This will cause the test to fail.

// Current (line 962)
contentId: attachment.contentId,

// Should be
contentId: attachment.contentId || undefined,

Fix this →

2. Potential race condition in total size tracking (outlook-provider.ts:926-936)

The total size check happens before the content is fetched, but totalSize is incremented after the attachment is added. If content fetching fails but metadata is still added, the size accounting remains correct. However, there's an edge case: if attachment.size is 0 or undefined, the check at line 926 uses attachment.size but line 996 uses attachment.size || 0. This inconsistency could theoretically allow more attachments through than intended.

// Line 926 - uses raw value
if (totalSize + attachment.size > MAX_TOTAL_ATTACHMENTS_SIZE) {

// Line 996 - uses fallback
totalSize += attachment.size || 0;

Consider using attachment.size || 0 consistently in the check as well.

3. Missing interface method in types (types/incoming-email.ts:287-290)

The getAttachments method was added to the interface, which is good. However, I notice it's added but not all implementations may be required to implement it. The interface documentation should clarify if this is optional for providers that don't support attachments.


Suggestions (Non-blocking)

Copilot's suggestion on attachment naming

Copilot suggested using a more descriptive fallback like attachment-{id}. This is reasonable for distinguishing unnamed attachments, though "unnamed" is acceptable if attachment IDs are logged elsewhere.

Test coverage for edge case

Consider adding a test for when attachment.size is 0 or missing to verify the size limit checks handle this correctly.


What Looks Good

  • Error resilience: Graceful degradation when content fetch fails (returns metadata without content)
  • Size limit enforcement: Both individual and total attachment size limits are properly enforced
  • Attachment type filtering: Correctly skips item attachments and reference attachments
  • Comprehensive logging: Good debug and warning logs for attachment processing decisions
  • Test coverage: 10 new test cases covering important scenarios including edge cases
  • Type definitions: Clean EmailAttachment interface with proper optional fields

Summary: This PR is well-implemented. The main issue to fix is the contentId null-to-undefined conversion (item 1). Item 2 is a minor inconsistency that should be addressed for robustness.

@London-Cat
Copy link
Collaborator

London-Cat commented Jan 27, 2026

📊 Reputation Summary

User Rep Pull Requests Activity Assigned Core Reactions
joeyorlando ⚡ 1999 82✅ 3🔄 15❌ 100 issues, 50 comments 6
CLAassistant ⚡ 0 0✅ 0🔄 0❌ 0 issues, 50 comments 0

How is the score calculated? Read about it in the Reputation Bot repository 🤖

@github-actions
Copy link
Contributor

Playwright test results

passed  309 passed
flaky  3 flaky
skipped  8 skipped

Details

stats  320 tests across 36 suites
duration  4 minutes, 19 seconds
commit  b6058d0

Flaky tests

api › api/mcp-gateway.spec.ts › MCP Gateway - External MCP Server Tests › should invoke internal-dev-test-server tool successfully
chromium › ui/mcp-install.spec.ts › MCP Install › Self-hosted from catalog
chromium › ui/mcp-install.spec.ts › MCP Install › Self-hosted from catalog

Skipped tests

api › api/chat-models.spec.ts › Chat Models Cache Invalidation API › should actually clear the cache so next request fetches fresh data
api › api/chat-models.spec.ts › Chat Models API › should fetch chat models from all providers
api › api/chat-models.spec.ts › Chat Models API › should fetch chat models filtered by provider (openai)
api › api/chat-models.spec.ts › Chat Models API › should fetch chat models filtered by provider (anthropic)
api › api/chat-models.spec.ts › Chat Models API › should fetch chat models filtered by provider (gemini)
api › api/chat-models.spec.ts › Chat Models API › should return empty array for invalid provider
api › api/chat-models.spec.ts › Chat Models API › should return consistent model structure across providers
api › api/chat-models.spec.ts › Chat Models API › should cache models (subsequent requests should be fast)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants