Conversation
SmtpSender added every attachment as a System.Net.Mail.Attachment, even when IsInline is true and a ContentId is set. The message then goes out as multipart/mixed with "Content-Disposition: attachment", so images referenced from the HTML body with <img src="cid:..."> are shown as separate attachments (Thunderbird shows them only as an attachment, Outlook shows them inline and as an attachment). Inline attachments with a ContentId are now added as LinkedResources of the HTML AlternateView, which produces multipart/related. When there is no plaintext alternative, an HTML body with inline attachments is put into an AlternateView for this. Regular attachments, plain-text bodies and inline attachments without a ContentId are unchanged.
|
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 13 |
| Duplication | 5 |
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Problem
SmtpSenderadds every attachment as aSystem.Net.Mail.Attachment, even whenIsInline = trueand aContentIdis set:The message is sent as
multipart/mixedand the image getsContent-Disposition: attachment:Mail clients then treat the image as an attachment. Thunderbird shows it only as an attachment, not in the body; Outlook shows it in the body and also as an attachment.
This has been reported on the original repository, see lukencode#101, with open PRs lukencode#276 and lukencode#325, and is still present in this fork.
Fix
Inline attachments that have a
ContentIdare added asLinkedResources of the HTMLAlternateView, which produces themultipart/relatedstructure mail clients expect for embedded images:AlternateViewgets the linked resources.AlternateViewso the resources can be linked to it.ContentId.The same message is now sent as:
With a regular attachment next to it, the structure is
multipart/mixedcontaining themultipart/relatedHTML part and the attachment.Tests
Three new tests in
SmtpSenderTestswrite the message to a pickup directory and check the MIME structure of the.eml:InlineAttachmentIsEmbeddedInHtmlBody:multipart/related,Content-ID: <logo>, no attachment disposition.InlineAttachmentIsEmbeddedInHtmlAlternateView: the same with a plaintext alternative, insidemultipart/alternative.RegularAttachmentStaysAttachmentNextToInlineAttachment:multipart/mixed; only the regular attachment hasContent-Disposition: attachment.All three fail without the fix and pass with it. The full test suite passes on net8.0, net9.0 and net10.0. The same approach is running in production for us, and the resulting e-mails were checked in Thunderbird and Outlook: the image shows only in the body.
Note
Building locally currently fails with
NU1902(a known vulnerability advisory for the MailKit 4.14.1 dependency, treated as an error because ofTreatWarningsAsErrors). That is unrelated to this change; I ran the tests with-p:NuGetAudit=false.