using System.Net.Http.Headers; using System.Net.Http.Json; using Microsoft.Extensions.Logging; namespace SIFinance.Shared; // Envoie des notifications par email via Microsoft Graph (permission application // Mail.Send, déjà accordée) — envoie "au nom de" une boîte du tenant (ex. le // demandeur), pas besoin de boîte de service dédiée. Les échecs sont journalisés mais // n'interrompent jamais le flux appelant (une notification ratée ne doit pas faire // échouer la création d'une demande). Vit dans SIFinance.Shared car les modules // (Achats, Sous-Traitants...) doivent pouvoir l'appeler directement. public class NotificationEmailService( IHttpClientFactory httpClientFactory, EntraGraphTokenProvider tokenProvider, ILogger logger) { public async Task EnvoyerAsync(string expediteurEmail, string destinataireEmail, string sujet, string corpsHtml, CancellationToken ct) { try { var token = await tokenProvider.GetTokenAsync(ct); var http = httpClientFactory.CreateClient(); http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var payload = new { message = new { subject = sujet, body = new { contentType = "HTML", content = corpsHtml }, toRecipients = new[] { new { emailAddress = new { address = destinataireEmail } } }, }, saveToSentItems = false, }; var response = await http.PostAsJsonAsync( $"https://graph.microsoft.com/v1.0/users/{Uri.EscapeDataString(expediteurEmail)}/sendMail", payload, ct); if (!response.IsSuccessStatusCode) { var body = await response.Content.ReadAsStringAsync(ct); logger.LogWarning("Échec d'envoi d'email de notification ({Status}) : {Body}", response.StatusCode, body); } } catch (Exception ex) when (ex is not OperationCanceledException) { logger.LogWarning(ex, "Échec d'envoi d'email de notification à {Destinataire}.", destinataireEmail); } } }