Skip to content

feat: Add CID (Content-ID) support for inline/embedded images in emai…#54

Merged
nfMalde merged 19 commits intomainfrom
feature/cid-support
Jan 4, 2026
Merged

feat: Add CID (Content-ID) support for inline/embedded images in emai…#54
nfMalde merged 19 commits intomainfrom
feature/cid-support

Conversation

@nfMalde
Copy link
Owner

@nfMalde nfMalde commented Jan 4, 2026

Version (v2.2.1)

  • Added ContentId property to AttachmentModel

  • Added LinkedResources property to IMailerContextResult for inline attachments

  • Added AddLinkedResource methods to IAttachmentCollection (file, bytes, URL)

  • Updated MailClient.PrepareMessage to handle linked resources with proper Content-Disposition: inline

  • Added integration tests for CID functionality

  • Added example usage in example project

  • Updated README with CID documentation and examples

  • Updated CHANGELOG and package metadata

…ls (v2.2.1)

- Added ContentId property to AttachmentModel

- Added LinkedResources property to IMailerContextResult for inline attachments

- Added AddLinkedResource methods to IAttachmentCollection (file, bytes, URL)

- Updated MailClient.PrepareMessage to handle linked resources with proper Content-Disposition: inline

- Added integration tests for CID functionality

- Added example usage in example project

- Updated README with CID documentation and examples

- Updated CHANGELOG and package metadata
Copilot AI review requested due to automatic review settings January 4, 2026 00:50
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Content-ID (CID) support to the MailKitMailer library, enabling inline/embedded images in HTML emails. This is a valuable feature that allows images to be embedded directly in emails and referenced via cid: URLs, ensuring they display correctly even when external image loading is disabled.

Key Changes

  • Added ContentId property to AttachmentModel and LinkedResources collection to IMailerContextResult for managing inline attachments
  • Implemented AddLinkedResource methods on IAttachmentCollection with support for file paths, byte arrays, and URLs
  • Updated MailClient.PrepareMessage to process linked resources with proper Content-Disposition: inline headers
  • Added comprehensive integration tests and example usage demonstrating the new CID functionality

Reviewed changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/AspNetCore.MailKitMailer/Models/AttachmentModel.cs Added ContentId property for CID references
src/AspNetCore.MailKitMailer/Domain/IMailerContextResult.cs Added LinkedResources property interface definition
src/AspNetCore.MailKitMailer/Data/MailerContextResult.cs Implemented LinkedResources property
src/AspNetCore.MailKitMailer/Domain/IAttachmentCollection.cs Added five AddLinkedResource method signatures for different source types
src/AspNetCore.MailKitMailer/Data/AttachmentCollection.cs Implemented AddLinkedResource methods
src/AspNetCore.MailKitMailer/Data/MailClient.cs Added linked resource processing logic and helper method
src/AspNetCore.MailKitMailer/AspNetCore.MailKitMailer.csproj Updated version to 2.2.1 and release notes
tests/AspNetCore.MailKitMailerIntegrationTests/LinkedResourceTests.cs Added integration tests for all CID scenarios
tests/Test-Apps/IntegrationTestsWebApp/Mailer/TestMailer.cs Added test mailer methods for linked resources
tests/Test-Apps/IntegrationTestsWebApp/Controllers/AttachmentTestController.cs Added controller endpoints for testing
tests/Test-Apps/IntegrationTestsWebApp/Mailer-Views/TestMailer/*.cshtml Added Razor views with CID references
tests/Test-Apps/IntegrationTestsWebApp/TestData/TestImage.png Added test image for integration tests
examples/MailKitMailerExample/Mailer/TestMailer.cs Added example implementation with inline logo
examples/MailKitMailerExample/Mailer/ITestMailer.cs Added interface definition for example
examples/MailKitMailerExample/Mailer-Views/TestMailer/WelcomeMailWithLogo.cshtml Added view template using CID
examples/MailKitMailerExample/Controllers/TestController.cs Added example controller endpoint
README.md Added comprehensive CID documentation with examples and API reference
CHANGELOG.md Documented the new features in version 2.2.1

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

netDumbster's SMTP test server has limited support for parsing
multipart/related MIME messages with linked resources. The tests
now verify that emails with linked resources are sent successfully
without asserting on the parsed MIME structure.
- Added AddLinkedResource methods on IAttachmentCollection for file paths, byte arrays, and URLs
- Added ContentId property to AttachmentModel
- Attachments with ContentId are automatically treated as linked resources (inline MIME disposition)
- Updated documentation with step-by-step examples
- Updated tests to use Shouldly assertions
- Removed unused LinkedResources property from IMailerContextResult
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 8 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

nfMalde and others added 2 commits January 4, 2026 09:03
- Remove unused fileName variable in MailClient.cs
- Remove extra blank line in TestMailer.cs
- Add cid:testimage verification to all LinkedResource tests for consistency
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Jan 4, 2026

@nfMalde I've opened a new pull request, #55, to work on those changes. Once the pull request is ready, I'll request review from you.

- Remove deprecated AddLinkedResource(byte[], string, string, string) overload
- Update signature to (byte[], string contentType, string contentId, string? fileName)
- Update callers to use new parameter order
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 312 to 319
if (isLinkedResource)
{
att = new MimePart(attachment.ContenType);
} else
var linkedResource = bodyBuilder.LinkedResources.Add(attachment.FilePath);
linkedResource.ContentId = attachment.ContentId;
if (attachment.FileName != null)
{
linkedResource.ContentDisposition!.FileName = attachment.FileName;
}
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FilePath handling for linked resources ignores the ContentType if it's set. When a user calls AddLinkedResource(string filePath, string contentType, string contentId, string? fileName = null), the contentType parameter is stored in attachment.ContenType but never used when creating the linked resource.

The code should check if attachment.ContenType is set and use it, similar to how FileBytes and FileUrl are handled. For example, it should parse the contentType and pass it to the BodyBuilder's LinkedResources.Add method.

Copilot uses AI. Check for mistakes.
nfMalde and others added 2 commits January 4, 2026 10:40
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@nfMalde
Copy link
Owner Author

nfMalde commented Jan 4, 2026

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Jan 4, 2026

@nfMalde I've opened a new pull request, #56, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits January 4, 2026 09:46
Co-authored-by: nfMalde <5366984+nfMalde@users.noreply.github.com>
fix: Honor ContentType parameter for FilePath-based linked resources
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 26 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +185 to +209
[HttpGet("linked-resource-url")]
public IActionResult TestLinkedResourceUrl()
{
string testuri = "http://localhost:3333/dl/TestImage.png";
Uri downloadUri = new Uri(testuri);

this.client.Send<ITestMailer>(x =>
x.Test_LinkedResource_Url(downloadUri, "testimage")
);

return Ok();
}

[HttpGet("linked-resource-url-async")]
public async Task<IActionResult> TestLinkedResourceUrlAsync()
{
string testuri = "http://localhost:3333/dl/TestImage.png";
Uri downloadUri = new Uri(testuri);

await this.client.SendAsync<ITestMailer>(x =>
x.Test_LinkedResource_UrlAsync(downloadUri, "testimage")
);

return Ok();
}
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The download server endpoint at /dl/{name}.{ext} serves text content ("TestDownload"), not actual image files. This means these URL-based tests are downloading text but treating it as an image file. The tests may pass due to lenient MIME handling, but they don't properly validate that actual image content is being downloaded and embedded. Consider updating the download server to serve the actual TestImage.png file, or add assertions that verify the downloaded content type and size match expected image data.

Copilot uses AI. Check for mistakes.
Comment on lines 298 to 341
else if (attachment.FilePath != null)
{
MimePart? att = null;

if (attachment.ContenType != null)
if (isLinkedResource)
{
att = new MimePart(attachment.ContenType);
} else
var fname = Path.GetFileName(attachment.FilePath);
var contentType = attachment.ContenType != null
? ContentType.Parse(attachment.ContenType)
: ContentType.Parse(MimeKit.MimeTypes.GetMimeType(fname));
var fileName = attachment.FileName ?? fname;
var data = await File.ReadAllBytesAsync(attachment.FilePath);

var linkedResource = bodyBuilder.LinkedResources.Add(fileName, data, contentType);
linkedResource.ContentId = attachment.ContentId;
}
else
{
att = new MimePart(MimeKit.MimeTypes.GetMimeType(attachment.FilePath));
if (!string.IsNullOrEmpty(attachment.ContenType))
{
var contentType = ContentType.Parse(attachment.ContenType);
var fileName = attachment.FileName ?? Path.GetFileName(attachment.FilePath);
var data = await File.ReadAllBytesAsync(attachment.FilePath);
bodyBuilder.Attachments.Add(fileName, data, contentType);
}
else
{
bodyBuilder.Attachments.Add(attachment.FilePath);
if (attachment.FileName != null)
{
var att = bodyBuilder.Attachments[bodyBuilder.Attachments.Count - 1];
att.ContentDisposition!.FileName = attachment.FileName;
}
}
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The refactored code now loads entire files into memory using File.ReadAllBytesAsync when handling file path attachments with an explicit content type (lines 328-331) or for linked resources (lines 314-322). The original code used File.OpenRead which created a stream, allowing MailKit to handle large files more efficiently without loading them entirely into memory. This change could cause memory issues when attaching large files. Consider using the stream-based approach for consistency with line 335 where bodyBuilder.Attachments.Add(attachment.FilePath) is still used for files without an explicit content type.

Copilot uses AI. Check for mistakes.
@nfMalde
Copy link
Owner Author

nfMalde commented Jan 4, 2026

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Contributor

Copilot AI commented Jan 4, 2026

@nfMalde I've opened a new pull request, #57, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI and others added 5 commits January 4, 2026 10:14
Co-authored-by: nfMalde <5366984+nfMalde@users.noreply.github.com>
Co-authored-by: nfMalde <5366984+nfMalde@users.noreply.github.com>
Co-authored-by: nfMalde <5366984+nfMalde@users.noreply.github.com>
Co-authored-by: nfMalde <5366984+nfMalde@users.noreply.github.com>
fix: Use stream-based file handling and serve actual test images
@nfMalde nfMalde merged commit 5517f61 into main Jan 4, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants