Skip to content

Support attachments for Outlook calendar events #2

@theakshaypant

Description

@theakshaypant

Summary

Google Calendar events include file attachments (name, URL, MIME type) in the response. Outlook currently skips attachments entirely. The Microsoft Graph SDK exposes GetHasAttachments() and GetAttachments() on events, but fetching them requires additional query parameters. Modern Outlook defaults to OneDrive/SharePoint links (which already have URLs), but raw file uploads are also possible.

Current behavior

  • Google: Extracts attachments from the event payload directly. Each attachment has a title, fileUrl (Google Drive link), and mimeType, mapped to core.Attachment.
  • Outlook: parseGraphEvent in events.go does not read attachments. The Attachments field on core.Event is always nil.

What needs to change

1. Expand attachments in the query

Graph API doesn't return attachment data by default. The event query needs $expand=attachments added as a query parameter so attachment metadata comes back inline with each event.

In events.go (fetchEventsFromCalendar), the request configuration needs to include:

requestConfig.QueryParameters.Expand = []string{"attachments"}

2. Handle attachment types

Graph API has three attachment types:

Type What it is URL
ReferenceAttachment OneDrive/SharePoint link (default in modern Outlook) GetSourceUrl() — already a clickable link, direct parallel to Google Drive links
FileAttachment Raw file uploaded to the event Construct https://graph.microsoft.com/v1.0/me/events/{event-id}/attachments/{attachment-id}/$value
ItemAttachment Embedded Outlook items (emails, events) Skip — not useful for calendar display

ReferenceAttachment is the most common in practice since modern Outlook defaults to sharing OneDrive links rather than uploading file content.

3. Parse attachments from the Graph response

Each event's GetAttachments() returns a slice of attachment items. Relevant properties:

  • GetName() — file name (e.g. meeting-notes.pdf)
  • GetContentType() — MIME type (e.g. application/pdf)
  • GetSize() — file size in bytes
  • GetId() — attachment ID (needed for FileAttachment download URL)
  • GetSourceUrl() — direct link (ReferenceAttachment only)

4. Map to core.Attachment

// ReferenceAttachment (OneDrive/SharePoint link)
core.Attachment{
    Title:    getName(),
    FileURL:  getSourceUrl(),    // already a direct link
    MIMEType: getContentType(),
}

// FileAttachment (raw upload)
core.Attachment{
    Title:    getName(),
    FileURL:  fmt.Sprintf("https://graph.microsoft.com/v1.0/me/events/%s/attachments/%s/$value", eventID, attachmentID),
    MIMEType: getContentType(),
}

Edge cases

  • Large attachments: Graph API returns attachment content inline if $expand is used and the attachment is under 3MB. Larger attachments need a separate GET request. For tsk (read-only, metadata only), we only need the name/type/URL — not the content bytes.
  • Events with no attachments: GetHasAttachments() can be checked first to skip parsing when there are none.
  • Pagination interaction: Verify that $expand=attachments works correctly with the existing PageIterator for event pagination.

Effort

Small. The attachment model already exists in core.Attachment, the display toggle is already wired up, and Google already populates it. ReferenceAttachments (OneDrive links) are trivial — just read the source URL. FileAttachments need a constructed download URL. Most of the work is adding $expand=attachments to the query and type-switching on the attachment kind.

Generated by Claude Opus 4.6

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions