diff --git a/src/presentation/DigitalData.MessagingService.API/Controllers/EmailController.cs b/src/presentation/DigitalData.MessagingService.API/Controllers/EmailController.cs
index 64548a1..71181df 100644
--- a/src/presentation/DigitalData.MessagingService.API/Controllers/EmailController.cs
+++ b/src/presentation/DigitalData.MessagingService.API/Controllers/EmailController.cs
@@ -112,4 +112,130 @@ public class EmailController(IMediator mediator) : ControllerBase
return Ok(res);
}
#endregion Receive
+
+ #region IMAP Send
+ ///
+ /// Send an email using IMAP account credentials (via RabbitMQ queue).
+ /// After the message is sent, it is appended to the IMAP Sent Items folder.
+ ///
+ /// Email fields as form values
+ /// Optional uploaded files
+ /// Cancellation token
+ /// HTTP 202 Accepted with the queued event ID
+ [HttpPost("imap/send")]
+ [Consumes("multipart/form-data")]
+ [ProducesResponseType(StatusCodes.Status202Accepted)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ public async Task SendEmailViaImap(
+ [FromForm] PublishEmailViaImapCommand 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 });
+ }
+ #endregion IMAP Send
+
+ #region POP3 Receive
+ ///
+ /// Fetch emails from a POP3 mailbox.
+ /// Triggers an on-demand POP3 sync before returning results.
+ ///
+ /// Query parameters for filtering and fetching emails from the POP3 mailbox.
+ /// Optional filter to return only specific fields.
+ /// Cancellation token.
+ /// HTTP 200 with list of received emails.
+ [HttpGet("pop3")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task FetchEmailsViaPop3(
+ [FromQuery] ReadEmailViaPop3Query query,
+ [FromQuery] OnlyFilter? only = null,
+ CancellationToken cancellationToken = default)
+ {
+ var res = await mediator.Send(query, cancellationToken);
+
+ if (!res.Emails.Any())
+ return NotFound("No emails found matching the specified criteria.");
+
+ if (only == OnlyFilter.HtmlBody)
+ {
+ if (res.Emails.FirstOrDefault()?.HtmlBody is string htmlBody)
+ return Content(htmlBody, "text/html");
+ else
+ return NotFound();
+ }
+ else if (only == OnlyFilter.Uid)
+ return Ok(res.Emails.Select(e => e.Uid).ToList());
+ else
+ return Ok(res);
+ }
+ #endregion POP3 Receive
+
+ #region OAuth2 Send
+ ///
+ /// Send an email via SMTP using OAuth2 authentication (via RabbitMQ queue).
+ /// The account must have UseOAuth2 = true and valid OAuth2 credentials configured.
+ ///
+ /// Email fields as form values
+ /// Optional uploaded files
+ /// Cancellation token
+ /// HTTP 202 Accepted with the queued event ID
+ [HttpPost("oauth2/send")]
+ [Consumes("multipart/form-data")]
+ [ProducesResponseType(StatusCodes.Status202Accepted)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ public async Task SendEmailViaOAuth2(
+ [FromForm] PublishEmailViaOAuth2Command 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 });
+ }
+ #endregion OAuth2 Send
+
+ #region OAuth2 Receive
+ ///
+ /// Fetch emails from an IMAP mailbox using OAuth2 authentication.
+ /// The account must have UseOAuth2 = true and valid OAuth2 credentials configured.
+ ///
+ /// Query parameters for filtering and fetching emails.
+ /// Optional filter to return only specific fields.
+ /// Cancellation token.
+ /// HTTP 200 with list of received emails.
+ [HttpGet("oauth2/imap")]
+ [ProducesResponseType(StatusCodes.Status200OK)]
+ [ProducesResponseType(StatusCodes.Status400BadRequest)]
+ [ProducesResponseType(StatusCodes.Status404NotFound)]
+ public async Task FetchEmailsViaOAuth2(
+ [FromQuery] ReadEmailViaOAuth2Query query,
+ [FromQuery] OnlyFilter? only = null,
+ CancellationToken cancellationToken = default)
+ {
+ var res = await mediator.Send(query, cancellationToken);
+
+ if (!res.Emails.Any())
+ return NotFound("No emails found matching the specified criteria.");
+
+ if (only == OnlyFilter.HtmlBody)
+ {
+ if (res.Emails.FirstOrDefault()?.HtmlBody is string htmlBody)
+ return Content(htmlBody, "text/html");
+ else
+ return NotFound();
+ }
+ else if (only == OnlyFilter.Uid)
+ return Ok(res.Emails.Select(e => e.Uid).ToList());
+ else
+ return Ok(res);
+ }
+ #endregion OAuth2 Receive
}