Note that, /me
endpoint works only with permissions of Delegated type and delegated authentication flows like authorization code flow, interactive flow etc... that needs user interaction.
While working with permissions of Application type and client credentials flow, you must use /users/userId
endpoint.
Initially, register one Microsoft Entra ID application and grant Mail.Send
permission of Application type with consent as below:
In my case, I used below C# code to send mail with attachment via Microsoft Graph HTTP API:
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using Microsoft.Identity.Client;
namespace GraphSendMail
{
class Program
{
static async Task Main(string[] args)
{
string tenantId = "tenantId";
string clientId = "appId";
string clientSecret = "secret";
string senderUserId = "******@xxxxxxx.onmicrosoft.com";
string recipientEmail = "******@outlook.com";
string subject = "Test Email with PNG Attachment";
string bodyContent = "This email contains a PNG attachment sent via Microsoft Graph API.";
string filePath = @"C:\test\srilogo.png";
string accessToken = await GetAccessTokenAsync(tenantId, clientId, clientSecret);
if (!File.Exists(filePath))
{
Console.WriteLine("File not found: " + filePath);
return;
}
var fileBytes = File.ReadAllBytes(filePath);
var base64File = Convert.ToBase64String(fileBytes);
var emailMessage = new
{
message = new
{
subject = subject,
body = new
{
contentType = "Text",
content = bodyContent
},
toRecipients = new[]
{
new
{
emailAddress = new
{
address = recipientEmail
}
}
},
attachments = new List<object>
{
new Dictionary<string, object>
{
{ "@odata.type", "#microsoft.graph.fileAttachment" },
{ "name", Path.GetFileName(filePath) },
{ "contentType", "image/png" },
{ "contentBytes", base64File }
}
}
},
saveToSentItems = true
};
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase
};
string jsonPayload = JsonSerializer.Serialize(emailMessage, options);
using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string endpoint = $"https://graph.microsoft.com/v1.0/users/{senderUserId}/sendMail";
var content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");
HttpResponseMessage response = await httpClient.PostAsync(endpoint, content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Email sent successfully.");
}
else
{
string errorResponse = await response.Content.ReadAsStringAsync();
Console.WriteLine("Error sending email: " + response.StatusCode);
Console.WriteLine(errorResponse);
}
}
private static async Task<string> GetAccessTokenAsync(string tenantId, string clientId, string clientSecret)
{
IConfidentialClientApplication app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
var result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
return result.AccessToken;
}
}
}
To confirm that, I checked the same in user's Sent Items
folder where mail sent successfully with attachment as below:
Alternatively, you can directly use Microsoft Graph SDK code to send mail with attachment by referring this MS Article:
using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Graph.Models;
using Microsoft.Graph.Users.Item.SendMail;
class Program
{
static async Task Main(string[] args)
{
string tenantId = "tenantId";
string clientId = "appId";
string clientSecret = "secret";
string senderEmail = "******@xxxxxxx.onmicrosoft.com";
string recipientEmail = "******@outlook.com";
string subject = "Test Email with PNG Attachment";
string bodyContent = "This email contains a PNG attachment sent via Microsoft Graph API.";
string filePath = @"C:\test\srilogo.png";
var graphClient = GetGraphClient(tenantId, clientId, clientSecret);
if (!File.Exists(filePath))
{
Console.WriteLine("File not found: " + filePath);
return;
}
byte[] fileBytes = await File.ReadAllBytesAsync(filePath);
var requestBody = new SendMailPostRequestBody
{
Message = new Message
{
Subject = subject,
Body = new ItemBody
{
ContentType = BodyType.Text,
Content = bodyContent
},
ToRecipients = new List<Recipient>
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = recipientEmail
}
}
},
Attachments = new List<Microsoft.Graph.Models.Attachment>
{
new FileAttachment
{
OdataType = "#microsoft.graph.fileAttachment",
Name = Path.GetFileName(filePath),
ContentType = "image/png",
ContentBytes = fileBytes
}
}
},
SaveToSentItems = true
};
try
{
await graphClient.Users[senderEmail].SendMail.PostAsync(requestBody);
Console.WriteLine("Email sent successfully!");
}
catch (Exception ex)
{
Console.WriteLine($"Error sending email: {ex.Message}");
}
}
static GraphServiceClient GetGraphClient(string tenantId, string clientId, string clientSecret)
{
var options = new ClientSecretCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret, options);
var scopes = new[] { "https://graph.microsoft.com/.default" };
return new GraphServiceClient(clientSecretCredential, scopes);
}
}
Please do not forget to click "Accept the answer” and Yes
wherever the information provided helps you, this can be beneficial to other community members.
If you have any other questions or still running into more issues, let me know in the "comments" and I would be happy to help you.