Fixing Outlook attachment issues.
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Microsoft.Graph.Models;
|
using Microsoft.Graph.Models;
|
||||||
using MimeKit;
|
using MimeKit;
|
||||||
@@ -98,45 +97,6 @@ namespace Wino.Core.Extensions
|
|||||||
message.InternetMessageHeaders = GetHeaderList(mime);
|
message.InternetMessageHeaders = GetHeaderList(mime);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var part in mime.BodyParts)
|
|
||||||
{
|
|
||||||
if (part.IsAttachment)
|
|
||||||
{
|
|
||||||
// File attachment.
|
|
||||||
|
|
||||||
using var memory = new MemoryStream();
|
|
||||||
((MimePart)part).Content.DecodeTo(memory);
|
|
||||||
|
|
||||||
var bytes = memory.ToArray();
|
|
||||||
|
|
||||||
var fileAttachment = new FileAttachment()
|
|
||||||
{
|
|
||||||
ContentId = part.ContentId,
|
|
||||||
Name = part.ContentDisposition?.FileName ?? part.ContentType.Name,
|
|
||||||
ContentBytes = bytes,
|
|
||||||
};
|
|
||||||
|
|
||||||
message.Attachments.Add(fileAttachment);
|
|
||||||
}
|
|
||||||
else if (part.ContentDisposition != null && part.ContentDisposition.Disposition == "inline")
|
|
||||||
{
|
|
||||||
// Inline attachment.
|
|
||||||
|
|
||||||
using var memory = new MemoryStream();
|
|
||||||
((MimePart)part).Content.DecodeTo(memory);
|
|
||||||
|
|
||||||
var bytes = memory.ToArray();
|
|
||||||
var inlineAttachment = new FileAttachment()
|
|
||||||
{
|
|
||||||
IsInline = true,
|
|
||||||
ContentId = part.ContentId,
|
|
||||||
Name = part.ContentDisposition?.FileName ?? part.ContentType.Name,
|
|
||||||
ContentBytes = bytes
|
|
||||||
};
|
|
||||||
|
|
||||||
message.Attachments.Add(inlineAttachment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|||||||
25
Wino.Core/Misc/OutlookFileAttachment.cs
Normal file
25
Wino.Core/Misc/OutlookFileAttachment.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Wino.Core.Misc
|
||||||
|
{
|
||||||
|
public class OutlookFileAttachment
|
||||||
|
{
|
||||||
|
[JsonPropertyName("@odata.type")]
|
||||||
|
public string OdataType { get; } = "#microsoft.graph.fileAttachment";
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string FileName { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("contentBytes")]
|
||||||
|
public string Base64EncodedContentBytes { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("contentType")]
|
||||||
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("contentId")]
|
||||||
|
public string ContentId { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("isInline")]
|
||||||
|
public bool IsInline { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -236,7 +235,6 @@ namespace Wino.Core.Synchronizers
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Logger.Error(ex, "Synchronization failed for {Name}", Account.Name);
|
Logger.Error(ex, "Synchronization failed for {Name}", Account.Name);
|
||||||
Debugger.Break();
|
|
||||||
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ using Wino.Core.Domain.Models.Synchronization;
|
|||||||
using Wino.Core.Extensions;
|
using Wino.Core.Extensions;
|
||||||
using Wino.Core.Http;
|
using Wino.Core.Http;
|
||||||
using Wino.Core.Integration.Processors;
|
using Wino.Core.Integration.Processors;
|
||||||
|
using Wino.Core.Misc;
|
||||||
using Wino.Core.Requests;
|
using Wino.Core.Requests;
|
||||||
|
|
||||||
namespace Wino.Core.Synchronizers
|
namespace Wino.Core.Synchronizers
|
||||||
@@ -689,6 +690,11 @@ namespace Wino.Core.Synchronizers
|
|||||||
|
|
||||||
var outlookMessage = mimeMessage.AsOutlookMessage(false);
|
var outlookMessage = mimeMessage.AsOutlookMessage(false);
|
||||||
|
|
||||||
|
// Create attachment requests.
|
||||||
|
// TODO: We need to support large file attachments with sessioned upload at some point.
|
||||||
|
|
||||||
|
var attachmentRequestList = CreateAttachmentUploadBundles(mimeMessage, mailCopyId, request).ToList();
|
||||||
|
|
||||||
// Update draft.
|
// Update draft.
|
||||||
|
|
||||||
var patchDraftRequest = _graphClient.Me.Messages[mailCopyId].ToPatchRequestInformation(outlookMessage);
|
var patchDraftRequest = _graphClient.Me.Messages[mailCopyId].ToPatchRequestInformation(outlookMessage);
|
||||||
@@ -696,12 +702,60 @@ namespace Wino.Core.Synchronizers
|
|||||||
|
|
||||||
// Send draft.
|
// Send draft.
|
||||||
|
|
||||||
|
|
||||||
var sendDraftRequest = PreparePostRequestInformation(_graphClient.Me.Messages[mailCopyId].Send.ToPostRequestInformation());
|
var sendDraftRequest = PreparePostRequestInformation(_graphClient.Me.Messages[mailCopyId].Send.ToPostRequestInformation());
|
||||||
|
|
||||||
var sendDraftRequestBundle = new HttpRequestBundle<RequestInformation>(sendDraftRequest, request);
|
var sendDraftRequestBundle = new HttpRequestBundle<RequestInformation>(sendDraftRequest, request);
|
||||||
|
|
||||||
return [patchDraftRequestBundle, sendDraftRequestBundle];
|
return [.. attachmentRequestList, patchDraftRequestBundle, sendDraftRequestBundle];
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<IRequestBundle<RequestInformation>> CreateAttachmentUploadBundles(MimeMessage mime, string mailCopyId, IRequestBase sourceRequest)
|
||||||
|
{
|
||||||
|
var allAttachments = new List<OutlookFileAttachment>();
|
||||||
|
|
||||||
|
foreach (var part in mime.BodyParts)
|
||||||
|
{
|
||||||
|
var isAttachmentOrInline = part.IsAttachment ? true : part.ContentDisposition?.Disposition == "inline";
|
||||||
|
|
||||||
|
if (!isAttachmentOrInline) continue;
|
||||||
|
|
||||||
|
using var memory = new MemoryStream();
|
||||||
|
((MimePart)part).Content.DecodeTo(memory);
|
||||||
|
|
||||||
|
var base64String = Convert.ToBase64String(memory.ToArray());
|
||||||
|
|
||||||
|
var attachment = new OutlookFileAttachment()
|
||||||
|
{
|
||||||
|
Base64EncodedContentBytes = base64String,
|
||||||
|
FileName = part.ContentDisposition?.FileName ?? part.ContentType.Name,
|
||||||
|
ContentId = part.ContentId,
|
||||||
|
ContentType = part.ContentType.MimeType,
|
||||||
|
IsInline = part.ContentDisposition?.Disposition == "inline"
|
||||||
|
};
|
||||||
|
|
||||||
|
allAttachments.Add(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestInformation PrepareUploadAttachmentRequest(RequestInformation requestInformation, OutlookFileAttachment outlookFileAttachment)
|
||||||
|
{
|
||||||
|
requestInformation.Headers.Clear();
|
||||||
|
|
||||||
|
string contentJson = JsonSerializer.Serialize(outlookFileAttachment);
|
||||||
|
|
||||||
|
requestInformation.Content = new MemoryStream(Encoding.UTF8.GetBytes(contentJson));
|
||||||
|
requestInformation.HttpMethod = Method.POST;
|
||||||
|
requestInformation.Headers.Add("Content-Type", "application/json");
|
||||||
|
|
||||||
|
return requestInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare attachment upload requests.
|
||||||
|
return allAttachments.Select(outlookAttachment =>
|
||||||
|
{
|
||||||
|
var emptyPostRequest = _graphClient.Me.Messages[mailCopyId].Attachments.ToPostRequestInformation(new Attachment());
|
||||||
|
var modifiedAttachmentUploadRequest = PrepareUploadAttachmentRequest(emptyPostRequest, outlookAttachment);
|
||||||
|
|
||||||
|
return new HttpRequestBundle<RequestInformation>(modifiedAttachmentUploadRequest, sourceRequest);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<IRequestBundle<RequestInformation>> Archive(BatchArchiveRequest request)
|
public override IEnumerable<IRequestBundle<RequestInformation>> Archive(BatchArchiveRequest request)
|
||||||
|
|||||||
Reference in New Issue
Block a user