feat(platform): add inline image (CID) support for email previews#478
Conversation
Greptile SummaryImplemented end-to-end support for inline images in email previews by propagating Key changes:
Issues found:
Confidence Score: 4/5
|
| Filename | Overview |
|---|---|
| examples/integrations/gmail/connector.js | Extracts Content-ID header from Gmail attachments and strips angle brackets |
| examples/integrations/outlook/connector.js | Extracts contentId from Outlook attachment metadata and strips angle brackets |
| services/platform/convex/conversations/internal_actions.ts | Correlates connector data with file refs by index to populate contentId on download, handles duplicate filenames |
| services/platform/app/components/ui/data-display/email-preview.tsx | Adds replaceCidReferences function and applies CID→URL mapping before sanitization |
| services/platform/app/features/conversations/components/message.tsx | Builds CID map, filters inline attachments from display, auto-triggers download for unresolved inline images |
Flowchart
flowchart TD
A[Email Sync] --> B[Connector extracts Content-ID]
B --> C{Provider?}
C -->|Gmail| D[Parse Content-ID header<br/>Strip angle brackets]
C -->|Outlook| E[Read contentId field<br/>Strip angle brackets]
D --> F[Return EmailType with<br/>attachment.contentId]
E --> F
F --> G[Store in message metadata]
G --> H{Attachment downloaded?}
H -->|No| I[UI detects unresolved<br/>inline image]
I --> J[Auto-trigger download]
J --> K[downloadAttachmentsAction]
H -->|Yes| L[Build CID→URL map]
K --> M[Correlate by array index]
M --> N[Populate contentId from<br/>connector return data]
N --> O[Update attachment with<br/>storageId + url + contentId]
O --> L
L --> P[replaceCidReferences]
P --> Q[Replace src='cid:X' with<br/>src='URL']
Q --> R[Sanitize HTML]
R --> S[Render EmailPreview]
L --> T[Filter displayAttachments]
T --> U[Hide inline images<br/>from attachment list]
Last reviewed commit: 4814a25
📝 WalkthroughWalkthroughThis PR adds end-to-end support for propagating Content-ID (CID) metadata from email attachments across Gmail and Outlook connectors, frontend UI rendering, and backend services. The changes extract contentId from email headers in connectors, simplify Outlook API queries to fetch all attachment fields, enhance the EmailPreview component to replace cid: references with actual URLs via a cidMap prop, update the message component to build cidMap from attachments and auto-download inline images, extend Convex schemas and conversation actions to store and correlate contentId throughout the pipeline, and increase MAX_PASSES from 10 to 50. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts (beta)
Tip Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@examples/workflows/outlook-email-sync/config.json`:
- Around line 67-71: The config uses "expand": "attachments" without an explicit
nested $select which relies on Graph's defaults; update the request parameters
(the JSON entries with "select" and "expand": "attachments") to include an
attachments $select specifying the exact attachment properties you need (for
example id, name, contentType, size, isInline, lastModifiedDateTime and only
include contentBytes if you actually need payloads) so intent is explicit and
future-proof—apply the same change to the other similar blocks referenced (the
other "select"/"expand" occurrences).
In `@services/platform/app/features/conversations/components/message.tsx`:
- Around line 195-204: Normalize attachment Content‑ID values before inserting
into cidMap so CID keys match inline `cid:` references; inside the useMemo that
builds cidMap (the const cidMap = useMemo(...) block iterating
message.attachments), trim surrounding whitespace and remove leading/trailing
angle brackets from att.contentId (and optionally normalize case) and use that
cleaned value as the map key (still storing att.url as the value) so lookups for
`cid:...` in HTML will match.
- Around line 206-232: displayAttachments currently removes all inline
attachments (att.contentId), which hides unresolved items and prevents manual
retry; change the filter in the displayAttachments useMemo to only exclude
inline attachments that are resolved (i.e., have both contentId and a url) so
unresolved inline attachments remain visible for retry. Update the useMemo that
defines displayAttachments to something like filtering out attachments where
att.contentId && att.url (reference: displayAttachments, message.attachments),
and leave the auto-download logic using inlineDownloadTriggered and
onDownloadAttachments unchanged so users can still trigger downloads but can
also manually retry visible unresolved attachments.
In
`@services/platform/convex/node_only/integration_sandbox/helpers/run_with_passes.ts`:
- Line 23: Add rationale for the 50-pass limit or make it configurable: either
add a short inline comment next to MAX_PASSES explaining why 50 was chosen
(e.g., to support many inline images while relying on existing timeoutMs
safety), or introduce a DEFAULT_MAX_PASSES constant and add maxPasses to
RunWithPassesParams and to the runWithPasses parameter destructure (e.g., const
{ ..., maxPasses = DEFAULT_MAX_PASSES } = params) so callers can override the
limit; update usages of MAX_PASSES in runWithPasses to use the new maxPasses
variable.
Resolve cid: references in email HTML to actual attachment URLs so inline images render correctly. Connectors now extract Content-ID headers, the backend correlates them during attachment download, and the EmailPreview component replaces cid: src attributes with resolved URLs. Auto-triggers attachment download when unresolved inline images are detected.
2c70fab to
d88661d
Compare
Summary
cid:references to attachment URLscontentIdthrough the full pipeline: connectors (Gmail/Outlook) → schema → transform → UIChanges
Content-IDheaders from Gmail and Outlook attachment metadatacontentIdfield to attachment schemas (EmailType,emailAttachmentMetaSchema)contentIdon download; surfacecontentIdin transformEmailPreviewresolvescid:src attributes via a CID→URL map;Messagecomponent auto-triggers download for unresolved inline images and filters inline attachments from the displayed list$selectfilter) socontentIdis availableMAX_PASSESfrom 10 to 50 to handle emails with many inline imagesTest plan
replaceCidReferencesandEmailPreviewcomponent with CID mapcontentId)🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Improvements