namespace JobTrackerApi.Services.EmailProviders { /// /// Provider-neutral email operations so job correspondence can be sourced from Gmail, /// Microsoft Graph, generic IMAP, or manual/free-text entry behind a single seam. /// See docs/remaster/PRODUCT_DIRECTION.md (multi-provider email). Gmail is the first /// implementation (); the controller migration and additional /// providers land in follow-up slices. /// public interface IEmailProvider { /// Stable key: "gmail" | "microsoft" | "imap" | "manual". string ProviderKey { get; } /// The user's active connection for this provider, or null if not connected. Task GetConnectionAsync(string ownerUserId, CancellationToken cancellationToken); /// Search the user's mailbox. is provider-specific syntax. Task> SearchAsync(string ownerUserId, string? query, int maxResults, CancellationToken cancellationToken); /// All messages in a thread/conversation. Task> ListThreadMessagesAsync(string ownerUserId, string threadId, CancellationToken cancellationToken); /// Full message content (body + attachments metadata). Task GetMessageAsync(string ownerUserId, string messageId, CancellationToken cancellationToken); } public sealed record EmailConnectionInfo(string ProviderKey, string Address); public sealed record EmailMessageSummary(string Id, string ThreadId, string Subject, string From, string To, DateTimeOffset? Date, string Snippet); public sealed record EmailAttachmentRef(string? FileName, string? MimeType, long? SizeBytes, string? ExternalAttachmentId, bool Inline); public sealed record EmailMessageDetail( string Id, string ThreadId, string Subject, string From, string To, DateTimeOffset? Date, string Snippet, string BodyText, string? BodyHtml, IReadOnlyList Labels, IReadOnlyList Attachments); /// Resolves a registered by its key. public interface IEmailProviderRegistry { IReadOnlyList All { get; } IEmailProvider? Get(string? providerKey); } public sealed class EmailProviderRegistry : IEmailProviderRegistry { private readonly Dictionary _byKey; public EmailProviderRegistry(IEnumerable providers) { All = providers.ToList(); _byKey = All.ToDictionary(p => p.ProviderKey, StringComparer.OrdinalIgnoreCase); } public IReadOnlyList All { get; } public IEmailProvider? Get(string? providerKey) => !string.IsNullOrWhiteSpace(providerKey) && _byKey.TryGetValue(providerKey, out var p) ? p : null; } }