Commit Graph

74 Commits

Author SHA1 Message Date
82be3c5a4f Refactor configuration handling
Refactored `MessagingServiceApplicationConfiguration` to simplify the tracking of the LuckyPennySoft license key configuration by replacing the `_configured` tuple with a boolean. Removed email account configuration methods from this class.

Updated `MessagingServiceInfrastructureConfiguration` to introduce a new `_configured` tuple for tracking `RabbitMqConnectionFactory` and `EmailAccounts` configurations. Added methods for configuring email accounts and updated the `EnsureRabbitMqConnectionFactoryAdded` method to include email account checks.

Changed the namespace of `EmailAccountsOptions.cs` to `DigitalData.MessagingService.Infrastructure.Options`.

Modified `Program.cs` to include email account configuration in the infrastructure setup.

Added new files `DependencyInjectionExtensions.cs` and `MessagingServiceConfiguration.cs` as placeholders for future extensions, wrapped in `#if NET` directives.

Removed an `<ItemGroup>` from `DigitalData.MessagingService.Infrastructure.csproj` and updated `DigitalData.MessagingService.Client.csproj` for XML compliance.
2026-11-02 15:23:21 +01:00
084ddc4b56 refactor(application): introduce MessagingServiceApplicationConfiguration builder
Replace the implicit IConfiguration-based DI registration with an explicit
builder that validates required steps at startup.

- Add MessagingServiceApplicationConfiguration with mandatory steps:
    SetLuckyPennySoftLicenseKey(), ConfigureEmailAccounts() / PublishOnly()
- EnsureConfigured() throws at registration time if either step is missing,
  surfacing misconfiguration before the app starts
- Keep the IConfiguration convenience overload as a thin wrapper over the
  builder for backward-compatible call sites
- Move DependencyInjection.cs into a DependencyInjection/ subfolder alongside
  the new configuration class
2026-11-02 15:02:07 +01:00
8e397d8119 fix(options): relax EmailAccountsOptions properties from init-only to set
init-only properties cannot be mutated by Options configure delegates.
Switching to set allows the builder pattern to bind values post-construction.
Also narrows Accounts type from IEnumerable to List for index access.
2026-11-02 15:01:56 +01:00
9bd100c0c5 Rename service registration method for clarity
Renamed the method in `DependencyInjection.cs` from `AddApplicationServices` to `AddMessagingServiceApplication` to better reflect its purpose related to the Messaging Service Application. Updated the corresponding method call in `Program.cs` to ensure consistency and correct service registration.
2026-11-02 10:52:37 +01:00
26c78d32ae Remove encryption service and related configurations
The `IEncryptionService` interface and its implementation,
`DataProtectionEncryptionService`, have been removed from the
codebase. These components previously provided encryption and
decryption functionality using the ASP.NET Core Data Protection API.

Additionally, the dependency injection setup for the encryption
service and the Data Protection API configuration (e.g., key
persistence and application name) have been removed from
`DependencyInjection.cs`.
2026-08-18 15:49:44 +02:00
8450806916 Refactor email fetching and handling logic
Consolidated email fetching queries into a unified `ReadEmailQuery` to support multiple protocols (IMAP, IMAP OAuth2, POP3) dynamically. Removed redundant query handlers (`ReadEmailViaImapQuery`, `ReadEmailViaOAuth2Query`, `ReadEmailViaPop3Query`) and merged their functionality into `ReadEmailQueryHandler` with protocol-specific methods.

Updated `FetchEmailsQueryValidator` to validate the new query. Refactored `EmailController` to use the unified query, simplifying endpoints and consolidating functionality. Removed obsolete endpoints for POP3 and OAuth2 fetching.

Performed code cleanup, including removing redundant imports and consolidating attachment handling logic. Updated project version to `2.0.0-beta` to reflect these significant changes. Improved documentation to align with the new structure.
2026-08-18 15:26:21 +02:00
acf40684f8 refactor: rename ReadEmailQuery to ReadEmailViaImapQuery, rename PublishEmailCommand to PublishEmailViaSmtpCommand 2026-08-17 17:03:59 +02:00
c189a2d6ef refactor(application): change GetOAuth2AuthorizationUrlQuery to look up account by Username instead of Id 2026-08-17 16:05:16 +02:00
408ad14c9f feat(application): add IEmailSyncService interface and ForcedSyncIntervalSeconds option to EmailAccountsOptions 2026-08-17 16:05:02 +02:00
ba8f701223 feat(application): add OAuth2RefreshToken/OAuth2Provider to DTOs; guard refresh token from being overwritten on seed; add OAuth2MappingProfile 2026-08-17 15:05:28 +02:00
6d6e876d94 feat(application): add OAuth2 authorization flow commands and queries (GetGoogleAuthorizationUrl, CompleteGoogleAuthorization) 2026-08-17 15:05:12 +02:00
502ae5e07b feat(application): add IOAuth2AuthorizationService interface and UpdateAccountOAuth2RefreshTokenCommand handler 2026-08-17 15:04:57 +02:00
c90040db67 feat(domain): add OAuth2Provider enum and OAuth2RefreshToken/OAuth2Provider fields to EmailAccount 2026-08-17 15:04:41 +02:00
158b562007 feat(domain/application): add IncomingProtocol field to EmailAccount entity and account DTOs 2026-08-17 10:48:45 +02:00
a0f1fcddac feat(domain): add IncomingProtocol enum (None, Imap, Pop3, ImapOAuth2, Pop3OAuth2) 2026-08-17 10:48:33 +02:00
822c7b1352 feat(application): register AutoMapper mappings for new commands and add SendAndAppend to IImapEmailService 2026-08-17 10:15:13 +02:00
f7e95eb7f7 feat(application): add PublishEmailViaImap/OAuth2 commands and ReadEmailViaPop3/OAuth2 queries with handlers 2026-08-17 10:14:59 +02:00
a57429718d feat(application): extend DTOs with POP3/OAuth2 fields and add IMAP append flags to SendingEmailEvent 2026-08-17 10:14:44 +02:00
ef8df96e65 feat(application): add IOAuth2TokenService and IPop3EmailService interfaces 2026-08-17 10:14:31 +02:00
194ae11a40 feat(domain): add POP3 and OAuth2 credential fields to EmailAccount entity 2026-08-17 10:14:18 +02:00
6c698c95be Refactor ReadEmailQuery to return structured response
Updated ReadEmailQuery to return a new response type,
ReadEmailQueryResponse, which includes both email data
and metadata (e.g., LastSync). Added the Account property
to ReadEmailQuery for specifying the email account.

Refactored ReadEmailQueryHandler to:
- Use IImapEmailService to fetch LastSync metadata.
- Return ReadEmailQueryResponse instead of a collection
  of ReceivedEmailDto.

Introduced ReadEmailQueryResponse class to encapsulate
LastSync and Emails properties.

Updated EmailController to handle the new response
structure, ensuring compatibility with the updated
ReadEmailQuery and its handler.
2026-08-17 01:13:14 +02:00
d01a0ceaa6 Refactor IMAP sync caching and improve thread safety
Replaced `IMemoryCache` with a thread-safe `ConcurrentDictionary`
for managing IMAP sync dates in `LimilabsImapEmailService`. Added
`GetLastImapSyncDate` and `SetLastImapSyncDate` methods to handle
cache operations. Updated the `IImapEmailService` interface to
include `GetLastImapSyncDate`. Simplified the `MarkAsSeenAsync`
method signature for better readability. Introduced a private
record type `ImapCacheKey` to encapsulate cache keys.
2026-08-14 08:40:56 +02:00
6abe0e18f6 feat(application): add EmailSyncResult DTO, Folder/AccountId to ReceivedEmailDto, rename CreateRangeAsync in IRepository, update IImapEmailService signature, add AutoMapper profiles for ReceivedEmail and EmailAttachment 2026-08-13 16:48:22 +02:00
c9b7d99ecc feat(domain): add Folder property and change To/Cc to List<string> in ReceivedEmail 2026-08-13 16:48:06 +02:00
4964fa4344 Refactor IMAP service for repository integration
Replaced `FetchEmailsAsync` with `SyncEmailsAsync` in `IImapEmailService` to simplify email synchronization. Updated method signatures to use `DateFilter` and added default parameters for `folder` and `cancel`.

Refactored `LimilabsImapEmailService` to remove client-side filtering logic and delegate storage to `IRepository<ReceivedEmail>`. Simplified IMAP search criteria to focus on date-based filtering and added checks to skip already-synced emails.

Updated `EmailSyncWorker` to use the new `SyncEmailsAsync` method. Removed unused code, streamlined exception handling, and improved maintainability by reducing complexity and focusing on server-side filtering.
2026-08-13 14:18:43 +02:00
7207c5b4d9 Refactor email repository and query handling
Replaced `IMailRepository` with `IReceivedEmailRepository` to improve modularity and functionality. Updated `IReceivedEmailRepository` to make the `EmailAccount` parameter optional in the `FindAsync` method.

Added `ReceivedEmailRepository` with advanced filtering capabilities, including account, flags, text, UID, date, and recipient filters. Implemented deferred materialization for recipient filtering due to EF Core limitations.

Registered `IReceivedEmailRepository` in dependency injection. Updated `ReadEmailQueryHandler` to use the new repository. Improved query performance by applying filters conditionally.
2026-08-13 13:28:19 +02:00
7f04c4b09f Rename IMailRepository and add FindAsync method
Renamed the `IMailRepository` interface to `IReceivedEmailRepository`
to better reflect its purpose. Added a new `FindAsync` method to
the interface, which supports searching for received emails using
a `MailSearchFilter`, an `EmailAccount`, and an optional
`CancellationToken`. The method returns a `Task` resolving to
an `IEnumerable<ReceivedEmail>`.
2026-08-13 13:18:37 +02:00
e73bead2f2 Refactor email fetching to use IMailRepository
Introduced a new `IMailRepository` interface to abstract email-fetching logic, replacing the direct dependency on `IImapEmailService` in `ReadEmailQueryHandler`. Updated `ReadEmailQueryHandler` to use `IMailRepository` for querying emails and added `IMapper` for mapping entities to DTOs.

Modified the constructor of `ReadEmailQueryHandler` to inject `IMailRepository`, `IMapper`, and renamed `IRepository<EmailAccount>` to `EmailAccountRepo`. Replaced `IImapEmailService.FetchEmailsAsync` with `IMailRepository.FindAsync` in the handler's `Handle` method.

Wrapped all changes in `#if NET` preprocessor directives to ensure compatibility with specific build configurations. These changes improve modularity, testability, and separation of concerns.
2026-08-13 13:11:18 +02:00
606ff94a77 Rename FetchEmailsQuery to ReadEmailQuery
Renamed `FetchEmailsQuery` to `ReadEmailQuery` across the codebase, including its handler, validator, and usages in `EmailController`. Updated method signatures, dependencies, and XML documentation to reflect the new naming convention. Adjusted `ILogger` dependency in the handler to match the renamed class.
2026-08-13 12:09:44 +02:00
14180860d3 refactor(application): replace ISender dispatch with direct IRepository usage in email handlers
- FetchEmailsQuery, MarkEmailAsSeenCommand, PublishEmailCommand: resolve EmailAccount
  via IRepository<EmailAccount> instead of dispatching GetEmailAccountQuery through ISender
- Swap InvalidOperationException for BadRequestException when IMAP server is not configured
- Add ILogger to handlers; warn when multiple accounts match the lookup criteria
- EmailAccountsOptions.Accounts now typed as IEnumerable<EmailAccountModificationDto>
  instead of IEnumerable<EmailAccount> to decouple config from domain entity
- EmailMappingProfile: add EmailAccount <-> EmailAccountDto/EmailAccountModificationDto maps
2026-08-13 11:57:57 +02:00
50eaefb868 refactor(application): replace GetSenderQuery with GetEmailAccountQuery and add EmailAccountModificationCommand
- Rename GetSenderQuery to GetEmailAccountQuery with updated return type (IEnumerable<EmailAccountDto>)
- Handler now queries IRepository<EmailAccount> directly instead of chaining MediatR dispatches
- Add EmailAccountModificationCommand for create/update/delete operations on email accounts
- Update GetSenderQueryValidator to reference renamed query type
- Remove exclusive Id/Username validation rule (now handled by repo query logic)
2026-08-13 11:57:39 +02:00
84da5cb646 feat(application): add EmailAccount DTOs and Modification value object 2026-08-13 11:57:25 +02:00
25b55ef651 feat(domain): add BadRequestException for invalid request errors 2026-08-13 11:57:12 +02:00
00ae8e1ba0 Add bulk create and upsert methods to repository
Added `CreateAsync` for bulk entity creation and `UpsertAsync`
and `UpsertSingleAsync` for upsert operations in `IRepository`
and `Repository`. Improved error handling in `UpdateSingleAsync`
and `DeleteSingleAsync` by throwing `NotFoundException` when no
matching entity is found. Refactored `FindAsync` and `UpdateAsync`
for better readability and performance. Cleaned up formatting in
`DeleteAsync`.
2026-08-13 09:36:48 +02:00
be28a61d9c Add email domain entities and .NET Framework support
Introduced `EmailAccount`, `EmailAttachment`, and `ReceivedEmail`
entities with database mappings using data annotations. These
entities represent email account configurations, attachments,
and received emails, respectively.

Added conditional compilation to ensure compatibility between
.NET and .NET Framework. Updated `DigitalData.MessagingService.Domain.csproj`
to include `System.ComponentModel.DataAnnotations` for `net462`.

Defined relationships between entities, including navigation
properties and foreign key constraints.
2026-08-12 16:08:29 +02:00
b2857c558f Refactor: Replace EmailAccountDto with EmailAccount
Replaced the `EmailAccountDto` class with the `EmailAccount` class across the codebase to consolidate the `EmailAccount` entity into the domain layer. Updated namespaces, method signatures, property types, and test cases to reflect this change.

Moved `EmailAccount` from `DigitalData.MessagingService.Application.Common.Dto` to `DigitalData.MessagingService.Domain.Entities`. Updated XML documentation and removed redundant project file entries. Adjusted namespaces for related queries, validators, and commands to align with the new structure.

These changes improve separation of concerns and align with domain-driven design principles.
2026-08-12 15:26:15 +02:00
91581649ba Refactor namespaces and remove Abstraction project
Replaced `DigitalData.MessagingService.Abstraction` with
`DigitalData.MessagingService.Application.Common.Dto` and
`DigitalData.MessagingService.Application.Common.Dto.MailSearch`
to improve modularity and organization.

Removed the `Abstraction` project and updated all references
to use the `Application` project. Updated namespaces, `using`
directives, and dependencies across the codebase.

Refactored interfaces, commands, queries, validators, and
services to use the new DTOs. Updated RabbitMQ integration,
AutoMapper profiles, background services, and tests to align
with the new structure.

Performed general cleanup by removing redundant `using`
directives and obsolete references.
2026-08-12 15:13:15 +02:00
4dd0974c6f Add multi-targeting support for .NET frameworks
Introduced conditional compilation using `#if NET` directives to
enable support for multiple frameworks (`net462`, `net480`, and
`net8.0`). Updated the project file to support multi-targeting
and added framework-specific dependencies conditionally.

Refactored namespaces, interfaces, classes, validators, and
handlers to ensure compatibility with targeted frameworks.
Enhanced dependency injection setup and adjusted logic in
`GetSenderQueryHandler` for framework-specific behavior.

Ensured consistency and maintainability by wrapping framework-
specific code blocks with `#if NET` directives.
2026-08-12 14:40:47 +02:00
5e0de6d52a Refactor email services and update password handling
Updated `EmailAccountDto` to use `required` properties for .NET 7+ compatibility, removing the `PasswordEncrypted` property and simplifying password handling.

Removed `IEncryptionService` dependency from `LimilabsEmailService` and `LimilabsImapEmailService`. Updated `ConnectAndAuthenticateSmtpAsync` and `OpenAsync` methods to remove password decryption logic.

Introduced `CancellationToken` support in `LimilabsImapEmailService` methods to improve cancellation handling for IMAP operations.

Added `Entities\` folder reference in `DigitalData.MessagingService.Domain.csproj`.
2026-08-12 14:24:17 +02:00
176e6dd6c5 Refactor: Replace EmailAttachmentContext with DTO
Replaced `EmailAttachmentContext` with `EmailAttachmentDto` across the codebase to align with the updated DTO naming convention.

- Renamed `EmailAttachmentContext` to `EmailAttachmentDto`.
- Updated property types, method signatures, and return types to use `EmailAttachmentDto`.
- Modified XML documentation references to reflect the new class name.
- Updated `ReceivedEmailContext` to `ReceivedEmailDto` and adjusted related methods and properties.
- Refactored `FetchEmailsAsync` methods and handlers to use `ReceivedEmailDto`.
- Adjusted `BuildAttachmentsAsync` and attachment handling logic in `EmailController` and `LimilabsImapEmailService`.

This refactor ensures consistency and improves code clarity while maintaining functionality.
2026-08-12 14:17:24 +02:00
cb3b2e09ab Refactor email fetching logic in EmailController
Consolidated email fetching endpoints by removing `FetchEmailUids`
and `FetchEmailByUid` endpoints and integrating their functionality
into the `FetchEmails` method. Introduced an `OnlyFilter` enum to
allow filtering responses for HTML body or UIDs. Removed related
methods (`FetchEmailUidsAsync`, `FetchEmailByUidAsync`) from
`IImapEmailService` and deleted associated query classes and
handlers.
2026-08-12 12:42:15 +02:00
a446162afa Add EmailSyncWorker and enhance IMAP service with caching
Refactored `ReceivedEmailContext` to use `record` for immutability
and value-based equality. Added `SyncIntervalSeconds` to
`EmailAccountsOptions` for configuring IMAP sync intervals.

Introduced `EmailSyncWorker` as a background service for periodic
email synchronization. Registered `IMemoryCache` and integrated
caching in `LimilabsImapEmailService` to reduce redundant fetch
operations. Optimized `FetchEmailByUidAsync` to conditionally
handle attachments and improve performance.

Refactored logging and improved code readability by adopting modern
C# features like `record`, `with` expressions, and `IOptions`.
Performed general cleanup and streamlined method implementations.
2026-08-12 11:48:29 +02:00
f521683608 /s
Simplify IMAP email fetching API and refactor logic

Removed `markAsSeen` parameter from `FetchEmailsAsync` and
`FetchEmailByUidAsync` methods in `IImapEmailService` to
simplify the API. Updated `MailSearchFilter` to make `MaxCount`
nullable for greater flexibility.

Removed `markAsSeen` from `FetchEmailByUidQuery` and
`FetchEmailsQuery` records and their handlers. Deleted
`FetchEmailByUidQueryValidator` as it is no longer needed.

Refactored `LimilabsImapEmailService`:
- Introduced `FetchEmailUidsAsync` to centralize UID fetching logic.
- Simplified `FetchEmailByUidAsync` using a new helper method.
- Consolidated connection, authentication, and folder selection
  into reusable private methods.
- Removed redundant code for search criteria and flag fetching.

Removed `IsSeen` from `ReceivedEmailContext` and improved
overall code readability and maintainability by reducing
duplication and centralizing logic.
2026-08-12 10:04:48 +02:00
e840d026aa feat(imap): add markAsSeen option to fetch queries and interface
- IImapEmailService.FetchEmailsAsync / FetchEmailByUidAsync now accept
  a bool markAsSeen = true parameter
- FetchEmailsQuery and FetchEmailByUidQuery expose MarkAsSeen { init; } = true
- markAsSeen=true  uses BODY[]      (server sets \\Seen, legacy-compatible)
- markAsSeen=false uses BODY.PEEK[] (non-destructive read, flag untouched)
2026-08-11 15:51:57 +02:00
59e8780345 Add FetchEmailUidsQuery and its handler for IMAP UIDs
Introduced `FetchEmailUidsQuery` to retrieve UIDs of matching
emails from an IMAP mailbox. Added the `FetchEmailUidsQuery`
record with properties for email account (`GetSenderQuery`)
and mail filtering (`MailSearchFilter`).

Implemented `FetchEmailUidsQueryHandler` to handle the query.
The handler validates the email account, ensures IMAP
configuration, and uses `IImapEmailService.FetchEmailUidsAsync`
to fetch UIDs. Added necessary `using` directives for
dependencies.
2026-08-11 09:46:26 +02:00
5ff38391d0 Add FetchEmailByUidQuery with handler and validation
Introduced `FetchEmailByUidQuery` to fetch a single email by its
UID from an IMAP mailbox. The query includes properties for
email account, UID, folder, and attachment inclusion, with a
fluent method `WithUid(long uid)` to set the UID.

Added `FetchEmailByUidQueryHandler` to process the query,
leveraging `ISender` for account retrieval and `IImapEmailService`
for email fetching. Included error handling for missing accounts
and misconfigured IMAP settings.

Implemented `FetchEmailByUidQueryValidator` to validate the
query, ensuring the `Account` is not null, `Uid` is set and
greater than 0, and `Folder` is not empty.
2026-08-11 09:45:21 +02:00
1fb7dcf98a Add methods for fetching email UIDs and emails by UID
Added `FetchEmailUidsAsync` to `IImapEmailService` for retrieving UIDs of emails matching a filter, optimizing scenarios where only identifiers are needed. Added `FetchEmailByUidAsync` to fetch a single email by UID, with optional attachment handling.

Implemented `FetchEmailUidsAsync` in `LimilabsImapEmailService` to connect to the IMAP server, construct search criteria, retrieve UIDs, and handle sorting and result limits. Added robust error handling for authentication and other failures.

Implemented `FetchEmailByUidAsync` in `LimilabsImapEmailService` to fetch email content and flags for a specific UID, map the data to `ReceivedEmailContext`, and handle errors with logging for non-critical failures.
2026-08-11 09:42:04 +02:00
ee279c407b Remove HasAttachments filter; enhance FetchEmails response
The `MailSearchFilter` class was updated to remove the `HasAttachments` property, simplifying the filtering logic. Corresponding client-side filtering logic in `LimilabsImapEmailService` was also removed. The IMAP search query now defaults to `Expression.All` when no criteria are provided.

The `FetchEmails` method in `EmailController` was enhanced with a new optional `firstHtmlBodyOnly` parameter. This allows returning only the HTML body of the first email or a `404 Not Found` response if no emails match the criteria. These changes improve flexibility and simplify the codebase.
2026-08-10 14:22:45 +02:00
74ec00ddd3 Refactor attachment handling in email fetching
Consolidate `WithAttachments` behavior into `MailSearchFilter` to simplify the API and reduce redundancy.

- Removed `withAttachments` parameter from `FetchEmailsAsync` in `IImapEmailService`.
- Added `WithAttachments` property to `MailSearchFilter` to control attachment inclusion.
- Removed `WithAttachments` property from `FetchEmailsQuery` as it is now encapsulated in `MailSearchFilter`.
- Updated `FetchEmailsQueryHandler` to use `MailSearchFilter` for attachment handling.
- Refactored `LimilabsImapEmailService` to use `MailSearchFilter.WithAttachments` for mapping email data.

These changes improve maintainability and clarity by centralizing attachment-related options in `MailSearchFilter`.
2026-08-10 12:05:27 +02:00
763ba67d34 Add support for optional email attachments fetching
Introduced a `withAttachments` parameter to the `FetchEmailsAsync` method in `IImapEmailService` and related layers, allowing callers to include or exclude attachment data when fetching emails. Updated `FetchEmailsQuery` and `FetchEmailsQueryHandler` to propagate this parameter.

Refactored `LimilabsImapEmailService` to conditionally process attachments and inline visuals based on the `withAttachments` flag, improving performance when attachments are not required. Replaced `Flag.Unseen` with `Expression.HasFlag(Flag.Unseen)` for better criteria handling. Cleaned up attachment-processing logic for improved readability and maintainability.
2026-08-10 11:54:35 +02:00