using DigitalData.MessagingService.Application.EmailSending.Commands;
using DigitalData.MessagingService.Application.EmailReceiving.Queries;
using DigitalData.MessagingService.Application.EmailReceiving.Commands;
using DigitalData.MessagingService.Application.EmailAccount.Queries;
using DigitalData.MessagingService.Abstraction;
using MediatR;
using Microsoft.AspNetCore.Mvc;
namespace DigitalData.MessagingService.API.Controllers;
///
/// Email sending API controller.
/// Enqueues outgoing emails to RabbitMQ for async processing.
///
[ApiController]
[Route("api/[controller]")]
public class EmailController(IMediator mediator) : ControllerBase
{
///
///
///
public enum OnlyFilter
{
///
///
///
HtmlBody,
///
///
///
Uid,
}
#region Send
///
/// Send an email, optionally with file attachments.
/// Omit the attachments field for a plain send.
///
/// Email fields as form values
/// Optional uploaded files
/// Cancellation token
/// HTTP 202 Accepted with the queued event ID
[HttpPost]
[Consumes("multipart/form-data")]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task SendEmail(
[FromForm] PublishEmailCommand command,
IFormFileCollection? attachments,
CancellationToken cancellationToken)
{
var commandWithAttachments = command.WithAttachments(
await BuildAttachmentsAsync(attachments, cancellationToken));
var eventId = await mediator.Send(commandWithAttachments, cancellationToken);
return Accepted(new { Id = eventId });
}
private static async Task> BuildAttachmentsAsync(
IFormFileCollection? files,
CancellationToken cancellationToken)
{
if (files is null || files.Count == 0)
return [];
var result = new List(files.Count);
foreach (var file in files)
{
using var ms = new MemoryStream();
await file.CopyToAsync(ms, cancellationToken);
result.Add(new EmailAttachmentContext
{
FileName = file.FileName,
Content = ms.ToArray(),
ContentType = file.ContentType
});
}
return result;
}
#endregion Send
#region Receive
///
/// Fetch emails from an IMAP mailbox.
///
/// Query parameters for filtering and fetching emails from the IMAP mailbox.
///
/// Cancellation token.
/// HTTP 200 with list of received emails.
[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task FetchEmails([FromQuery] FetchEmailsQuery query, [FromQuery] OnlyFilter? only = null, CancellationToken cancellationToken = default)
{
var emails = await mediator.Send(query, cancellationToken);
if(!emails.Any())
return NotFound("No emails found matching the specified criteria.");
if (only == OnlyFilter.HtmlBody)
{
if (emails.FirstOrDefault()?.HtmlBody is string htmlBody)
return Content(htmlBody, "text/html");
else
return NotFound();
}
else if (only == OnlyFilter.Uid)
return Ok(emails.Select(e => e.Uid).ToList());
else
return Ok(emails);
}
#endregion Receive
}