Add support for email attachments in messaging service
Introduced the `EmailAttachmentContext` class to represent email attachments, with properties for file name, content, content type, inline display behavior, and content ID. Used conditional compilation to support both .NET Framework and .NET versions. Updated the `EmailContext` class to include an `Attachments` property, enabling emails to include attachments as byte arrays or file paths. Enhanced the `LimilabsEmailService` class to handle attachments: - Added the `AddAttachments` method to process inline and regular attachments. - Integrated attachment handling into the email-building process.
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
namespace DigitalData.MessagingService.Abstraction;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a single email attachment.
|
||||
/// </summary>
|
||||
public sealed class EmailAttachmentContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Display name of the attachment (e.g. "invoice.pdf").
|
||||
/// </summary>
|
||||
#if NETFRAMEWORK
|
||||
public string FileName { get; set; } = null!;
|
||||
#else
|
||||
public required string FileName { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Raw content of the attachment.
|
||||
/// </summary>
|
||||
#if NETFRAMEWORK
|
||||
public byte[] Content { get; set; } = null!;
|
||||
#else
|
||||
public required byte[] Content { get; init; }
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// MIME content-type (e.g. "application/pdf", "image/png").
|
||||
/// Defaults to "application/octet-stream" when not specified.
|
||||
/// </summary>
|
||||
public string ContentType { get; set; } = "application/octet-stream";
|
||||
|
||||
/// <summary>
|
||||
/// When <see langword="true"/> the attachment is embedded inline and displayed
|
||||
/// directly inside the email body via a CID reference (e.g. <img src="cid:logo">).
|
||||
/// When <see langword="false"/> (default) it appears as a regular downloadable attachment.
|
||||
/// </summary>
|
||||
public bool IsInline { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Content-ID used when <see cref="IsInline"/> is <see langword="true"/>.
|
||||
/// Reference it in HTML body as <c>cid:{ContentId}</c>.
|
||||
/// Auto-generated from <see cref="FileName"/> when left empty.
|
||||
/// </summary>
|
||||
public string? ContentId { get; set; }
|
||||
}
|
||||
@@ -45,4 +45,11 @@ public record EmailContext
|
||||
#else
|
||||
public bool IsHtml { get; init; } = true;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Optional list of attachments to include with the email.
|
||||
/// Each entry may carry its content as a byte array (<see cref="EmailAttachmentContext.Content"/>)
|
||||
/// or reference a file on disk via <see cref="EmailAttachmentContext.FilePath"/>.
|
||||
/// </summary>
|
||||
public IEnumerable<EmailAttachmentContext> Attachments { get; set; } = [];
|
||||
}
|
||||
@@ -46,6 +46,8 @@ public class LimilabsEmailService(
|
||||
else
|
||||
builder.Text = context.Body;
|
||||
|
||||
AddAttachments(builder, context.Attachments);
|
||||
|
||||
var mail = builder.Create();
|
||||
|
||||
result = await smtp.SendMessageAsync(mail, cancellationToken);
|
||||
@@ -108,4 +110,33 @@ public class LimilabsEmailService(
|
||||
|
||||
return message.ToString();
|
||||
}
|
||||
|
||||
private static void AddAttachments(MailBuilder builder, IEnumerable<EmailAttachmentContext> attachments)
|
||||
{
|
||||
foreach (var attachment in attachments)
|
||||
{
|
||||
if (attachment.IsInline)
|
||||
{
|
||||
var visual = builder.AddVisual(attachment.Content);
|
||||
visual.FileName = attachment.FileName;
|
||||
visual.ContentId = string.IsNullOrWhiteSpace(attachment.ContentId)
|
||||
? attachment.FileName
|
||||
: attachment.ContentId;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(attachment.ContentType))
|
||||
visual.ContentType = ContentType.Parse(attachment.ContentType);
|
||||
}
|
||||
else
|
||||
{
|
||||
var part = builder.AddAttachment(attachment.Content);
|
||||
part.FileName = attachment.FileName;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(attachment.ContentType))
|
||||
part.ContentType = ContentType.Parse(attachment.ContentType);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(attachment.ContentId))
|
||||
part.ContentId = attachment.ContentId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user