OSX 邮件应用渲染了两次内联图像
Inline image rendered twice by OSX mail app
我的 .NET 4.5 Web 应用程序使用 class SmtpClient 创建电子邮件消息并将其发送给不同的收件人。
每封电子邮件包含:
- HTML 邮件正文
- 嵌入的内联图像(JPeg、PNG 或 GIF)
- 附件 (PDF)
示例代码如下。它工作正常,但 OSX 用户有一个抱怨。 Apple 的标准邮件应用程序将图像渲染两次;一次内嵌在邮件正文中,然后再次跟随邮件正文,在 PDF 附件的预览旁边。
我修改了以下属性; none 其中有帮助。
- SmtpClient 的交付格式
- MailMessage 的 IsBodyHtml 和 BodyTransferEncoding
- Attachment 的 MimeType、Inline、DispositionType、ContentId、FileName、Size、CreationDate、ModificationDate
如果我在 MS Outlook 中撰写一封类似的电子邮件并将其发送给 Apple 用户,则图像会呈现一次,内嵌在邮件正文中;完全符合我的意愿。所以显然 是 可能的。
阅读 this 后,我检查了原始 MIME 数据,发现 Outlook 使用 multipart/related
将邮件正文和图像组合在一起。
我的问题:
如何使用 System.Net.Mail 中的 classes 模仿 Outlook 的行为?
我不想做的事情:
- 使用外部图像而不是嵌入式图像(许多电子邮件客户端最初会阻止这些图像以保护收件人的隐私)。
- 使用第三方库(避免法律纠纷)。我发现 here 的 SmtpDirect class 似乎解决了问题(尽管我在 return 中得到了服务器异常),但我很难接受完全重写 MS 的 SmtpClient 实现是如此微妙的变化是必要的。
- 将电子邮件消息发送到拾取文件夹,处理生成的
.eml
文件,将文件推送到我们的 Exchange 服务器。
重现问题的最少代码:
using System.IO;
using System.Net.Mail;
using System.Net.Mime;
namespace SendMail
{
class Program
{
const string body = "Body text <img src=\"cid:ampersand.gif\" /> image.";
static Attachment CreateGif()
{
var att = new Attachment(new MemoryStream(Resource1.ampersand), "ampersand.gif")
{
ContentId = "ampersand.gif",
ContentType = new ContentType(MediaTypeNames.Image.Gif)
};
att.ContentDisposition.Inline = true;
return att;
}
static Attachment CreatePdf()
{
var att = new Attachment(new MemoryStream(Resource1.Hello), "Hello.pdf")
{
ContentId = "Hello.pdf",
ContentType = new ContentType(MediaTypeNames.Application.Pdf)
};
att.ContentDisposition.Inline = false;
return att;
}
static MailMessage CreateMessage()
{
var msg = new MailMessage(Resource1.from, Resource1.to, "The subject", body)
{
IsBodyHtml = true
};
msg.Attachments.Add(CreateGif());
msg.Attachments.Add(CreatePdf());
return msg;
}
static void Main(string[] args)
{
new SmtpClient(Resource1.host).Send(CreateMessage());
}
}
}
要实际构建并 运行 它,您将需要一个额外的资源文件 Resource1.resx
,其中包含两个附件(ampersand
和 Hello
)和三个字符串 host
(SMTP 服务器)、from
和 to
(均为电子邮件地址)。
(我在发布问题之前自己找到了这个解决方案,但还是决定发布;它可能会对其他人有所帮助。我仍然愿意接受其他解决方案!)
我设法通过使用 class AlternateView.
获得了预期的效果
static MailMessage CreateMessage()
{
var client = new SmtpClient(Resource1.host);
var msg = new MailMessage(Resource1.from, Resource1.to, "The subject", "Alternative message body in plain text.");
var view = AlternateView.CreateAlternateViewFromString(body, System.Text.Encoding.UTF8, MediaTypeNames.Text.Html);
var res = new LinkedResource(new MemoryStream(Resource1.ampersand), new ContentType(MediaTypeNames.Image.Gif))
{
ContentId = "ampersand.gif"
};
view.LinkedResources.Add(res);
msg.AlternateViews.Add(view);
msg.Attachments.Add(CreatePdf());
return msg;
}
作为副作用,邮件现在还包含正文的纯文本版本(对于拒绝 HTML 的偏执 Web 客户端)。虽然它有点负担("Alternative message body in plain text" 需要改进),但它确实让您可以更好地控制消息在不同安全设置下的呈现方式。
我的 .NET 4.5 Web 应用程序使用 class SmtpClient 创建电子邮件消息并将其发送给不同的收件人。 每封电子邮件包含:
- HTML 邮件正文
- 嵌入的内联图像(JPeg、PNG 或 GIF)
- 附件 (PDF)
示例代码如下。它工作正常,但 OSX 用户有一个抱怨。 Apple 的标准邮件应用程序将图像渲染两次;一次内嵌在邮件正文中,然后再次跟随邮件正文,在 PDF 附件的预览旁边。
我修改了以下属性; none 其中有帮助。
- SmtpClient 的交付格式
- MailMessage 的 IsBodyHtml 和 BodyTransferEncoding
- Attachment 的 MimeType、Inline、DispositionType、ContentId、FileName、Size、CreationDate、ModificationDate
如果我在 MS Outlook 中撰写一封类似的电子邮件并将其发送给 Apple 用户,则图像会呈现一次,内嵌在邮件正文中;完全符合我的意愿。所以显然 是 可能的。
阅读 this 后,我检查了原始 MIME 数据,发现 Outlook 使用 multipart/related
将邮件正文和图像组合在一起。
我的问题: 如何使用 System.Net.Mail 中的 classes 模仿 Outlook 的行为?
我不想做的事情:
- 使用外部图像而不是嵌入式图像(许多电子邮件客户端最初会阻止这些图像以保护收件人的隐私)。
- 使用第三方库(避免法律纠纷)。我发现 here 的 SmtpDirect class 似乎解决了问题(尽管我在 return 中得到了服务器异常),但我很难接受完全重写 MS 的 SmtpClient 实现是如此微妙的变化是必要的。
- 将电子邮件消息发送到拾取文件夹,处理生成的
.eml
文件,将文件推送到我们的 Exchange 服务器。
重现问题的最少代码:
using System.IO;
using System.Net.Mail;
using System.Net.Mime;
namespace SendMail
{
class Program
{
const string body = "Body text <img src=\"cid:ampersand.gif\" /> image.";
static Attachment CreateGif()
{
var att = new Attachment(new MemoryStream(Resource1.ampersand), "ampersand.gif")
{
ContentId = "ampersand.gif",
ContentType = new ContentType(MediaTypeNames.Image.Gif)
};
att.ContentDisposition.Inline = true;
return att;
}
static Attachment CreatePdf()
{
var att = new Attachment(new MemoryStream(Resource1.Hello), "Hello.pdf")
{
ContentId = "Hello.pdf",
ContentType = new ContentType(MediaTypeNames.Application.Pdf)
};
att.ContentDisposition.Inline = false;
return att;
}
static MailMessage CreateMessage()
{
var msg = new MailMessage(Resource1.from, Resource1.to, "The subject", body)
{
IsBodyHtml = true
};
msg.Attachments.Add(CreateGif());
msg.Attachments.Add(CreatePdf());
return msg;
}
static void Main(string[] args)
{
new SmtpClient(Resource1.host).Send(CreateMessage());
}
}
}
要实际构建并 运行 它,您将需要一个额外的资源文件 Resource1.resx
,其中包含两个附件(ampersand
和 Hello
)和三个字符串 host
(SMTP 服务器)、from
和 to
(均为电子邮件地址)。
(我在发布问题之前自己找到了这个解决方案,但还是决定发布;它可能会对其他人有所帮助。我仍然愿意接受其他解决方案!)
我设法通过使用 class AlternateView.
获得了预期的效果static MailMessage CreateMessage()
{
var client = new SmtpClient(Resource1.host);
var msg = new MailMessage(Resource1.from, Resource1.to, "The subject", "Alternative message body in plain text.");
var view = AlternateView.CreateAlternateViewFromString(body, System.Text.Encoding.UTF8, MediaTypeNames.Text.Html);
var res = new LinkedResource(new MemoryStream(Resource1.ampersand), new ContentType(MediaTypeNames.Image.Gif))
{
ContentId = "ampersand.gif"
};
view.LinkedResources.Add(res);
msg.AlternateViews.Add(view);
msg.Attachments.Add(CreatePdf());
return msg;
}
作为副作用,邮件现在还包含正文的纯文本版本(对于拒绝 HTML 的偏执 Web 客户端)。虽然它有点负担("Alternative message body in plain text" 需要改进),但它确实让您可以更好地控制消息在不同安全设置下的呈现方式。