How Submit HTTP Mail Attachment through Microsoft Graph API?

WesWilliams-4769 45 Reputation points
2025-02-15T18:02:33.02+00:00

There are no examples anywhere on how to submit an http mail attachment to the Graph API. After 102 unsuccessful permutations, I am asking here. I have come to the conclusion that Graph has a bug in not allowing attachments - or is something known to only those who know a secret handshake.

The context is a standalone program using the ConfidentialClientApplicationBuilder (e.g. https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-daemon-dotnet-acquire-token). Emails are submitting using an httpClient with URL = $"https://graph.microsoft.com/v1.0/users/{userId}/sendMail" and not "$"https://graph.microsoft.com/v1.0/me/sendMail"

I can submit emails just fine. Just not attachments.

Here are 3 examples that do not work and one that did work using Powershell (but not c#, alas).

  1. Fails on .SendAsync {
{
   error": {
   "code": "RequestBodyRead",
   "message": "The property 'AdditionalData' does not exist on type 'microsoft.graph.attachment'. Make sure to only use property names that are defined by the type or mark the type as open type."
   }}
    /*
     * THIS WORKS WITHOUT ATTACHMENTS. FAILS WITH ATTACHMENTS
     * 
     *  "The property 'AdditionalData' does not exist on type 'microsoft.graph.attachment'. 
     *  Make sure to only use property names that are defined by the type or mark the type as open type."
     */
    var thisWorksWithoutAttachments = new
    {
        message = new
        {
            subject = "Test Email",
            body = new
            {
                contentType = "Text",
                content = "Hello, this is a test email!"
            },
            toRecipients = new[]
            {
                new
                {
                    emailAddress = new
                    {
                        address = "******@outlook.com"
                    }
                }
            },
            attachments = new List<Microsoft.Graph.Models.Attachment>()  // <== note Attachment but with an instance of FileAttachment per https://stackoverflow.com/questions/76152485/how-to-add-attachment-to-microsoft-graph-based-email
            {
                new Microsoft.Graph.Models.FileAttachment
                {
                    Name = "test.txt",
                    ContentType = "text/plain",
                    ContentBytes = Encoding.UTF8.GetBytes("Hello, this is a test attachment!"),
                    OdataType = "#microsoft.graph.fileAttachment",
                    IsInline = false,
                    Size = 1024,
                }
            }
        },
        saveToSentItems = "true"
    };
    var requestContent = new StringContent(JsonSerializer.Serialize(thisWorksWithoutAttachments));
    var userId = "******@yyy.onmicrosoft.com";
    requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://graph.microsoft.com/v1.0/users/{userId}/sendMail")
    { Content = requestContent };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
   
   var response = await httpClient.SendAsync(request);
  1. Fails similarly on .SendAsync. It's the same as above but the email is constructed using objects
{
  "error": {
     "code": "RequestBodyRead",
     "message": "The property 'AdditionalData' does not exist on type 'microsoft.graph.attachment'. Make sure to only use property names that are defined by the type or mark the type as open type."  
}}
    /*
     * FAILS WITH ATTACHMENTS
     * 
     *  "The property 'ContentBytes' does not exist on type 'microsoft.graph.attachment'. 
     *  Make sure to only use property names that are defined by the type or mark the type as open type."
     */
    var thisFailsMessage = new EmailMessage
    {
        Message = new Message
        {
            Subject = Random.Shared.Next() + " Text",
            Body = new ItemBody
            {
                ContentType = BodyType.Text.ToString(),
                Content = Random.Shared.Next() + " Hello, this is a test email! " + Random.Shared.Next()
            },
            ToRecipients =
            [
                new Recipient
                {
                    EmailAddress = new EmailAddress
                    {
                        Address = "******@outlook.com"
                    }
                }
            ],
            Attachments =
            [
                new FileAttachment
                {
                    Name = "test.txt",
                    ContentType = "text/plain",
                    OdataType = "#microsoft.graph.fileAttachment",       // <== this not needed since it is set in the FileAttachment 
                    AdditionalData = new Dictionary<string, object>()
                    {
                        { "contentId", "1234" },
                        { "lastModifiedDateTime", DateTimeOffset.UtcNow },
                        { "isInline", false },
                        { "size", 1024 },
                        { "contentBytes", Encoding.UTF8.GetBytes("Hello, this is a test attachment!")   }
                    }
                }
            ]
        },
        SaveToSentItems = true
    };

    var requestContent = new StringContent(JsonSerializer.Serialize(thisWorksWithoutAttachments));

    var userId = "******@yyy.onmicrosoft.com";
    requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    var request = new HttpRequestMessage(HttpMethod.Post, $"https://graph.microsoft.com/v1.0/users/{userId}/sendMail")
    { Content = requestContent };
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
    var response = await httpClient.SendAsync(request);
  1. Uses MultipartFormDataContent but Fails on .PostAsync {
{
  "error": {
    "code": "RequestBodyRead",
    "message": "A supported MIME type could not be found that matches the content type of the response. None of the supported type(s) 'Microsoft.OData.ODataMediaType, Microsoft.OData.ODataMediaType, Microsoft.OData.ODataMediaType, Microsoft.OData.ODataMediaTyp...' matches the content type 'multipart/form-data; boundary=\"Upload----02/15/2025 12:16:12\"'."
}}
static async Task SendMostafaAsync(HttpClient httpClient, string bearerToken)
{
    var userId = "******@yyy.onmicrosoft.com";
    var emailEndpoint = $"https://graph.microsoft.com/v1.0/users/{userId}/sendMail";
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);
    httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("multipart/mixed"));
    var filePath = "C:\\Users\\xxx\\source\\repos\\ms-identity-docs-code-dotnet\\console-daemon\\MostafaCode.png";
    using var multipartFormContent = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture));
    // Load the file and set the file's Content-Type header
    var fileStreamContent = new StreamContent(File.OpenRead(filePath));
    fileStreamContent.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");   // also tried 'image/png'
    // Add the file to the form content
    multipartFormContent.Add(fileStreamContent, "file", Path.GetFileName(filePath));
    // Add other form data if needed
    multipartFormContent.Add(new StringContent("******@outlook.com"), "to");
    multipartFormContent.Add(new StringContent("Subject of the email"), "subject");
    multipartFormContent.Add(new StringContent("Body of the email"), "body");
    // Create the HttpRequestMessage
    var request = new HttpRequestMessage(HttpMethod.Post, emailEndpoint)
    {
        Content = multipartFormContent
    };
    // Send the request
//    var response = await httpClient.SendAsync(request);
    // Send the request
    var response = await httpClient.PostAsync(emailEndpoint, multipartFormContent);
}

But THIS Powershell script DOES work. Why not the C#?

#Get File Name and Base64 string
$Attachment="C:\Users\\xxx\source\repos\ms-identity-docs-code-dotnet\console-daemon\MostafaCode.png"

$FileName=(Get-Item -Path $Attachment).name
$base64string = [Convert]::ToBase64String([IO.File]::ReadAllBytes($Attachment)) 

#Connect to GRAPH API $tokenBody = @{     
    Grant_Type    = "client_credentials"
    Scope         = "https://graph.microsoft.com/.default"
    Client_Id     = $clientId
    Client_Secret = $clientSecret
}
$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Method POST -Body $tokenBody
$headers = @{
    "Authorization" = "Bearer $($tokenResponse.access_token)"
    "Content-type"  = "application/json"
}

#Send Mail    
$URLsend = "https://graph.microsoft.com/v1.0/users/$MailSender/sendMail" 
$Body = @" {
                         "message": {
                          "subject": "Subject", 
                          "body": {
                            "contentType": "HTML",
                            "content": "Body"
                           },
                          
                          "toRecipients": [
                            {
                              "emailAddress": {
                                "address": "$Recipient"
                              }
                            }
                          ]
                          ,"attachments": [
                            {
                              "@odata.type": "#microsoft.graph.fileAttachment",
                              "name": "$FileName",
                              "contentType": "text/plain",
                              "contentBytes": "$base64string"
                            }
                          ]
                        },
                        "saveToSentItems": "false"
                      }
"@

Invoke-RestMethod -Method POST -Uri $URLsend -Headers $headers -Body $BodyJsonsend

Microsoft Graph
Microsoft Graph
A Microsoft programmability model that exposes REST APIs and client libraries to access data on Microsoft 365 services.
13,075 questions
Microsoft Exchange
Microsoft Exchange
Microsoft messaging and collaboration software.
688 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Tianyi Chang (Shanghai Wicresoft Co Ltd) 0 Reputation points Microsoft Vendor
    2025-02-19T01:12:31.8866667+00:00

    Hi, @WesWilliams-4769

    Welcome to the Microsoft Q&A platform!

    According to your description,this issue is more related to Microsoft Graph API, so I changed the tag to Microsoft Graph.

    Thank you for your understanding, and I hope your problem can be solved soon!

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.