Why Chunked File Download is Essential for Dynamics 365 Plugins Sending Emails via Third-Party APIs

A deep dive into the technical challenges of handling large file attachments in Dynamics 365 plugins and why traditional approaches fail when integrating with external email services.

The Problem: When Traditional File Retrieval Meets Third-Party APIs

If you’ve ever worked with Dynamics 365 plugins that need to send emails with attachments through third-party APIs (like external email services, cloud communication platforms, or enterprise messaging systems), you’ve likely encountered a frustrating scenario:

  1. Your plugin retrieves a file from Dynamics 365’s msdyn_richtextfilesentity
  2. The file appears to be there — you can see the record and metadata
  3. But when you try to access the actual file content, you get a GUID instead of the expected Base64 data
  4. Your third-party email API rejects the attachment because it’s not valid file data

This isn’t a bug — it’s by design. And understanding why is crucial for building robust Dynamics 365 integrations.

The Dynamics 365 File Storage Architecture

Dynamics 365 uses a sophisticated file storage system that’s optimized for performance and security. When files are stored in entities like

msdyn_richtextfiles

, they’re not stored as simple Base64 strings in a single field. Instead, Microsoft uses a chunked storage approach:

Traditional Approach (What Doesn’t Work)

// This approach fails for large files
var fileEntity = service.Retrieve("msdyn_richtextfiles", fileId,
new ColumnSet("msdyn_fileblob"));
var fileData = fileEntity.GetAttributeValue<byte[]>("msdyn_fileblob");
// Result: You get a GUID, not the actual file content!

The Reality: Chunked Storage

According to Microsoft’s documentation, large files are stored in chunks to:

  • Improve performance — Only load what you need
  • Reduce memory usage — Don’t load entire files into memory unnecessarily
  • Enable streaming — Process files as they’re downloaded
  • Support large files — Handle files larger than typical database field limits

The Chunked Download Solution

The solution is to use Dynamics 365’s built-in chunked download messages. Here’s how it works:

Step 1: Initialize File Blocks Download

var initializeRequest = new OrganizationRequest("InitializeFileBlocksDownload");
initializeRequest["FileAttributeName"] = "msdyn_fileblob";
initializeRequest["Target"] = new EntityReference("msdyn_richtextfiles", fileId);
var initializeResponse = service.Execute(initializeRequest);
int fileSize = (int)initializeResponse["FileSizeInBytes"];
string continuationToken = (string)initializeResponse["FileContinuationToken"];

Step 2: Download File in Chunks

var downloadedBytes = new List<byte>();
int offset = 0;
const int chunkSize = 4194304; // 4MB chunks
while (offset < fileSize)
{
var downloadRequest = new OrganizationRequest("DownloadBlock");
downloadRequest["Offset"] = offset;
downloadRequest["BlockLength"] = Math.Min(chunkSize, fileSize - offset);
downloadRequest["FileContinuationToken"] = continuationToken;
var downloadResponse = service.Execute(downloadRequest);
byte[] chunkData = (byte[])downloadResponse["Data"];
downloadedBytes.AddRange(chunkData);
offset += chunkData.Length;
}
byte[] completeFile = downloadedBytes.ToArray();

Why This Matters for Third-Party Email APIs

The Integration Challenge

When sending emails through third-party APIs, you need to provide actual file content, not GUIDs or Dynamics 365 image url or other secure link requiring authentication. Here’s what happens in a typical integration:

// ❌ This fails - third-party API gets a GUID instead of file data
var attachment = new EmailAttachment
{
Content = fileEntity.GetAttributeValue<byte[]>("msdyn_fileblob"), // This is a GUID!
Filename = "document.pdf",
ContentType = "application/pdf"
};
// ✅ This works - third-party API gets actual file content
var attachment = new EmailAttachment
{
Content = DownloadFileInChunks(service, fileId), // Actual file bytes
Filename = "document.pdf",
ContentType = "application/pdf"
};

Real-World Example: Enterprise Notification System

In a recent project for an enterprise notification system, we encountered this exact issue. The system needed to:

  1. Retrieve email templates from Dynamics 365 with embedded images
  2. Convert images to data URLs for email compatibility
  3. Send emails via external API with embedded images

Initial Problem:

// Images weren't displaying in emails
var imageData = imageEntity.GetAttributeValue<byte[]>("msdyn_imageblob");
// Result: null or empty - images not showing in emails

Solution with Chunked Download:

// Images now display correctly
var imageData = DownloadFileInChunks(service, imageId);
var base64Data = Convert.ToBase64String(imageData);
var dataUrl = $"data:image/png;base64,{base64Data}";
// Result: Images display in compatible email clients, fallback headers in others

Performance and Memory Considerations

Memory Efficiency

Chunked download is memory-efficient because:

  • Streaming approach — Process data as it’s downloaded
  • Configurable chunk size — Balance between memory usage and network requests
  • No memory spikes — Avoid loading entire files into memory at once

Network Optimization

// Optimize chunk size based on file size
int chunkSize = fileSize < 1024 * 1024 ? fileSize : 4194304; // 4MB for large files

Cross-Client Email Compatibility

One of the most interesting discoveries in our implementation was how different email clients handle embedded images:

Email Client A

  • ✅ Supports data URLs — Images display correctly
  • ✅ No additional processing needed — Direct embedding works

Email Client B

  • ❌ Blocks data URLs — Security policy prevents automatic image loading
  • ✅ Fallback solution — Professional text headers display instead

The Data URL Blocking Challenge

Many popular email clients (including major webmail providers) block

data:

URLs for security reasons. This is a common issue when sending emails with embedded images:

  • Security Concern: Data URLs can potentially contain malicious content
  • User Experience: Images appear as broken or missing
  • Solution: Implement fallback content that displays regardless of image support

Implementation Strategy

// Try data URL first, fallback to text header
if (emailClientSupportsDataUrls)
{
html = html.Replace(imageTag, $"<img src=\"{dataUrl}\" alt=\"Logo\">");
}
else
{
html = html.Replace(imageTag, fallbackTextHeader);
}

Best Practices for Production Systems

1. Error Handling

try
{
var fileData = DownloadFileInChunks(service, fileId);
// Process file data
}
catch (Exception ex)
{
// Log error and provide fallback
tracingService.Trace($"File download failed: {ex.Message}");
return fallbackContent;
}

2. Transaction Management

// Don't wrap OrganizationService calls in try-catch
// Let CRM handle transaction management
var response = service.Execute(downloadRequest);
// CRM will handle rollback if needed

3. Caching Strategy

// Cache downloaded files for repeated use
private static readonly Dictionary<Guid, byte[]> FileCache = new();
public byte[] GetCachedFile(Guid fileId)
{
if (!FileCache.ContainsKey(fileId))
{
FileCache[fileId] = DownloadFileInChunks(service, fileId);
}
return FileCache[fileId];
}

The Stack Overflow Connection

This issue is so common that it’s frequently discussed on Stack Overflow. As referenced in this Stack Overflow question, developers often encounter the same problem:

“The problem is that when I retrieve the msdyn_richtextfile record using the GUID, the msdyn_fileblob attribute does not contain the file data. Instead, it holds another GUID, and I cannot find documentation or a clear method to resolve this to the actual file content.”

The answer, as confirmed by the community, is to use the chunked download approach documented by Microsoft.

Conclusion

Chunked file download isn’t just a technical detail — it’s essential for building robust Dynamics 365 integrations with third-party services. Understanding this architecture helps you:

  • Build reliable integrations that work with real-world file sizes
  • Optimize performance through efficient memory usage
  • Handle edge cases gracefully with proper error handling
  • Create cross-client compatible solutions for email systems

The next time you’re building a Dynamics 365 plugin that needs to send files through a third-party API, remember: the file isn’t where you think it is, and chunked download is your friend.

Have you encountered similar challenges with Dynamics 365 file handling? Share your experiences in the comments below!

Tags: #Dynamics365 #PluginDevelopment #FileHandling #ThirdPartyIntegration #EmailAPIs #ChunkedDownload #MicrosoftDynamics

Learn more Why Chunked File Download is Essential for Dynamics 365 Plugins Sending Emails via Third-Party APIs

Leave a Reply

Your email address will not be published. Required fields are marked *