diff --git a/src/core/DigitalData.MessagingService.Domain/DigitalData.MessagingService.Domain.csproj b/src/core/DigitalData.MessagingService.Domain/DigitalData.MessagingService.Domain.csproj
index 23957d0..de95276 100644
--- a/src/core/DigitalData.MessagingService.Domain/DigitalData.MessagingService.Domain.csproj
+++ b/src/core/DigitalData.MessagingService.Domain/DigitalData.MessagingService.Domain.csproj
@@ -11,4 +11,8 @@
+
+
+
+
diff --git a/src/core/DigitalData.MessagingService.Domain/Entities/EmailAccount.cs b/src/core/DigitalData.MessagingService.Domain/Entities/EmailAccount.cs
index 5530c92..f8bab17 100644
--- a/src/core/DigitalData.MessagingService.Domain/Entities/EmailAccount.cs
+++ b/src/core/DigitalData.MessagingService.Domain/Entities/EmailAccount.cs
@@ -1,52 +1,75 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
namespace DigitalData.MessagingService.Domain.Entities;
///
/// DTO for a single email account configuration.
///
+[Table("EMAIL_ACCOUNT")]
public class EmailAccount
{
///
/// Logical name to identify this account (e.g. "default", "support").
///
+ [Key]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ [Column("ID", TypeName = "int")]
public int Id { get; set; }
+ [Required]
+ [MaxLength(256)]
+ [Column("USERNAME", TypeName = "nvarchar(256)")]
#if NET
public required string Username { get; set; }
#else
public string Username { get; set; } = null!;
#endif
+ [Required]
+ [MaxLength(512)]
+ [Column("PASSWORD", TypeName = "nvarchar(512)")]
#if NET
public required string Password { get; set; }
#else
public string Password { get; set; } = null!;
#endif
+ [Required]
+ [MaxLength(256)]
+ [Column("SMTP_SERVER", TypeName = "nvarchar(256)")]
#if NET
public required string SmtpServer { get; set; }
#else
public string SmtpServer { get; set; } = null!;
#endif
+ [Column("SMTP_PORT", TypeName = "int")]
public int SmtpPort { get; set; }
+ [Column("SMTP_USE_SSL", TypeName = "bit")]
public bool SmtpUseSsl { get; set; }
+ [Column("USE_OAUTH2", TypeName = "bit")]
public bool UseOAuth2 { get; set; }
///
/// IMAP server hostname (e.g. "imap.example.com").
/// Leave empty when this account is send-only.
///
+ [MaxLength(256)]
+ [Column("IMAP_SERVER", TypeName = "nvarchar(256)")]
public string? ImapServer { get; set; }
///
/// IMAP server port (993 for SSL, 143 for plain/STARTTLS).
///
+ [Column("IMAP_PORT", TypeName = "int")]
public int ImapPort { get; set; } = 993;
///
/// Use SSL/TLS when connecting to the IMAP server.
///
+ [Column("IMAP_USE_SSL", TypeName = "bit")]
public bool ImapUseSsl { get; set; } = true;
}
\ No newline at end of file
diff --git a/src/core/DigitalData.MessagingService.Domain/Entities/EmailAttachment.cs b/src/core/DigitalData.MessagingService.Domain/Entities/EmailAttachment.cs
new file mode 100644
index 0000000..f7b4c61
--- /dev/null
+++ b/src/core/DigitalData.MessagingService.Domain/Entities/EmailAttachment.cs
@@ -0,0 +1,83 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace DigitalData.MessagingService.Domain.Entities;
+
+///
+/// Represents a single email attachment.
+///
+[Table("EMAIL_ATTACHMENT")]
+public sealed class EmailAttachment
+{
+ [Key]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ [Column("ID", TypeName = "bigint")]
+#if NET
+ public long Id { get; init; }
+#else
+ public long Id { get; set; }
+#endif
+
+ ///
+ /// Display name of the attachment (e.g. "invoice.pdf").
+ ///
+ [Required]
+ [MaxLength(260)]
+ [Column("FILE_NAME", TypeName = "nvarchar(260)")]
+#if NETFRAMEWORK
+ public string FileName { get; set; } = null!;
+#else
+ public required string FileName { get; init; }
+#endif
+
+ ///
+ /// Raw content of the attachment.
+ ///
+ [Required]
+ [Column("CONTENT", TypeName = "varbinary(max)")]
+#if NETFRAMEWORK
+ public byte[] Content { get; set; } = null!;
+#else
+ public required byte[] Content { get; init; }
+#endif
+
+ ///
+ /// MIME content-type (e.g. "application/pdf", "image/png").
+ /// Defaults to "application/octet-stream" when not specified.
+ ///
+ [Required]
+ [MaxLength(256)]
+ [Column("CONTENT_TYPE", TypeName = "nvarchar(256)")]
+ public string ContentType { get; set; } = "application/octet-stream";
+
+ ///
+ /// When the attachment is embedded inline and displayed
+ /// directly inside the email body via a CID reference (e.g. <img src="cid:logo">).
+ /// When (default) it appears as a regular downloadable attachment.
+ ///
+ [Column("IS_INLINE", TypeName = "bit")]
+ public bool IsInline { get; set; } = false;
+
+ ///
+ /// Content-ID used when is .
+ /// Reference it in HTML body as cid:{ContentId}.
+ /// Auto-generated from when left empty.
+ ///
+ [MaxLength(512)]
+ [Column("CONTENT_ID", TypeName = "nvarchar(512)")]
+ public string? ContentId { get; set; }
+
+ [ForeignKey(nameof(Email))]
+ [Column("EMAIL_ID", TypeName = "bigint")]
+#if NET
+ public long EmailId { get; init; }
+#else
+ public long EmailId { get; set; }
+#endif
+
+#if NET
+ public ReceivedEmail? Email { get; init; }
+#else
+ public ReceivedEmail? Email { get; set; }
+#endif
+}
diff --git a/src/core/DigitalData.MessagingService.Domain/Entities/ReceivedEmail.cs b/src/core/DigitalData.MessagingService.Domain/Entities/ReceivedEmail.cs
new file mode 100644
index 0000000..4b1eb4d
--- /dev/null
+++ b/src/core/DigitalData.MessagingService.Domain/Entities/ReceivedEmail.cs
@@ -0,0 +1,136 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace DigitalData.MessagingService.Domain.Entities;
+
+///
+/// Represents an email message received via IMAP.
+///
+[Table("RECEIVED_EMAIL")]
+public sealed record ReceivedEmail
+{
+ [Key]
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ [Column("ID", TypeName = "bigint")]
+#if NET
+ public long Id { get; init; }
+#else
+ public long Id { get; set; }
+#endif
+
+ ///
+ /// Unique identifier of the message on the IMAP server (UID).
+ ///
+ [Column("UID", TypeName = "bigint")]
+#if NET
+ public long Uid { get; init; }
+#else
+ public long Uid { get; set; }
+#endif
+
+ ///
+ /// Sender address (From header).
+ ///
+ [Required]
+ [MaxLength(512)]
+ [Column("FROM", TypeName = "nvarchar(512)")]
+#if NET
+ public string From { get; init; } = string.Empty;
+#else
+ public string From { get; set; } = string.Empty;
+#endif
+
+ ///
+ /// Recipient addresses (To header).
+ ///
+ [Column("TO", TypeName = "nvarchar(max)")]
+#if NET
+ public IEnumerable To { get; init; } = [];
+#else
+ public IEnumerable To { get; set; } = [];
+#endif
+
+ ///
+ /// CC addresses.
+ ///
+ [Column("CC", TypeName = "nvarchar(max)")]
+#if NET
+ public IEnumerable Cc { get; init; } = [];
+#else
+ public IEnumerable Cc { get; set; } = [];
+#endif
+
+ ///
+ /// Email subject.
+ ///
+ [MaxLength(998)]
+ [Column("SUBJECT", TypeName = "nvarchar(998)")]
+#if NET
+ public string Subject { get; init; } = string.Empty;
+#else
+ public string Subject { get; set; } = string.Empty;
+#endif
+
+ ///
+ /// Plain-text body (may be empty when only HTML is present).
+ ///
+ [Column("TEXT_BODY", TypeName = "nvarchar(max)")]
+#if NET
+ public string TextBody { get; init; } = string.Empty;
+#else
+ public string TextBody { get; set; } = string.Empty;
+#endif
+
+ ///
+ /// HTML body (may be empty when only plain-text is present).
+ ///
+ [Column("HTML_BODY", TypeName = "nvarchar(max)")]
+#if NET
+ public string HtmlBody { get; init; } = string.Empty;
+#else
+ public string HtmlBody { get; set; } = string.Empty;
+#endif
+
+ ///
+ /// Date/time the message was sent (Date header).
+ ///
+ [Column("DATE", TypeName = "datetime2")]
+#if NET
+ public DateTime Date { get; init; }
+#else
+ public DateTime Date { get; set; }
+#endif
+
+ ///
+ /// Whether the message has been marked as seen/read on the server.
+ ///
+ [Column("IS_SEEN", TypeName = "bit")]
+#if NET
+ public bool IsSeen { get; init; }
+#else
+ public bool IsSeen { get; set; }
+#endif
+
+ [ForeignKey(nameof(Account))]
+ [Column("ACCOUNT_ID", TypeName = "int")]
+#if NET
+ public int AccountId { get; init; }
+#else
+ public int AccountId { get; set; }
+#endif
+
+ ///
+ /// Attachments included with this message.
+ ///
+#if NET
+ public IEnumerable? Attachments { get; init; }
+#else
+ public IEnumerable? Attachments { get; set; }
+#endif
+
+#if NET
+ public EmailAccount? Account { get; init; }
+#else
+ public EmailAccount? Account { get; set; }
+#endif
+}