如何将图像流嵌入MailMessage

19

我在将Properties.Resources中的图像嵌入MailMessage时遇到了一些困难,当前收到的电子邮件中没有显示出该图像。

我已成功地从目录位置嵌入了图像,但更希望图像来自于内存/应用程序。

以下是我正在进行的简化版本。

 Bitmap b = new Bitmap(Properties.Resources.companyLogo);
 MemoryStream logo = new MemoryStream();
 b.Save(logo, ImageFormat.Jpeg);



 MailMessage newEmail = new MailMessage(from, to);
 newEmail.Subject = subject;
 newEmail.IsBodyHtml = true;

 LinkedResource footerImg = new LinkedResource(logo, "image/jpeg");
 footerImg.ContentId = "companyLogo";
 AlternateView foot= AlternateView.CreateAlternateViewFromString(body + "<p> <img src=cid:companyLogo /> </p>", null, "text/html");

 foot.LinkedResources.Add(footerImg);

 newEmail.AlternateViews.Add(foot);             

 SmtpClient server = new SmtpClient(host, port);
 server.Send(newEmail);

“head”来自哪里,你如何处理“foot”? - Massif
我已经解决了这个问题,简短的答案是不要使用Bitmap.Save,而是将图像转换为Byte[],并用它来实例化MemoryStream。稍后我会发布完整的答案。 - fluf
6个回答

28

好的,我已经解决了这个问题。

我没有使用BitMap保存方法,而是将BitMap转换为Byte[]并将Byte[]传给内存流。

之前不起作用:

 b.Save(logo, ImageFormat.Jpeg);

已经工作:

Bitmap b = new Bitmap(Properties.Resources.companyLogo);
ImageConverter ic = new ImageConverter();
Byte [] ba = (Byte[]) ic.ConvertTo(b,typeof(Byte[]));
MemoryStream logo = new MemoryStream(ba);

我认为这与Bitmap.Save方法有关,在MSDN库中提到流必须具有偏移量0。


告诉我们,兄弟,你是怎么发现这种方法的?+1 - NoWar

23
Bitmap b = new Bitmap(Properties.Resources.companyLogo);
MemoryStream logo = new MemoryStream();
b.Save(logo, ImageFormat.Jpeg);

保存操作后,您需要将MemoryStream的“位置指针”(即stream.Position)重新设置为开头(0)。

logo.Position = 0;

我想使用这种方法,但无法使其工作。附件始终为0大小。将位置设置为0就解决了问题!@Jeremy非常感谢 :-) - Xan-Kun Clark-Davis

3
您可以将图片转换为base64格式,以嵌入图片并跳过资源处理:
public static string BitmapToBase64(Bitmap b)
{
   ImageConverter ic = new ImageConverter();
   byte[] ba = (byte[])ic.ConvertTo(b, typeof(byte[]));
   return Convert.ToBase64String(ba, 0, ba.Length);
}

并将其用作HTML图像的src属性:

string logoimage="<img src='data:image/png;base64," + BitmapToBase64(logo) + "'>";

请注意,将图像转换为Base64会略微增加图像的大小。

2
不幸的是,一些网络邮件客户端与base64嵌入式图片的兼容性不太好。请参阅https://dev59.com/8nA75IYBdhLWcg3weY1f - Vinzz

0

可以试试看这里:

http://www.eggheadcafe.com/community/aspnet/2/10219822/send-mail-with-atttached-image.aspx

从上面的链接:

static void EmbedImages()
{
   var mail = new MailMessage();

   mail.From = new MailAddress("me@mycompany.com");
   mail.To.Add("you@yourcompany.com");
   mail.Subject = "This is an email";

   var plainView = AlternateView.CreateAlternateViewFromString(
      "This is my plain text content, viewable by those clients that don't support html",
      null, "text/plain");

   var htmlView = AlternateView.CreateAlternateViewFromString(
      "Here is an embedded image.<img src=cid:companylogo>", 
      null, "text/html");

   LinkedResource logo = new LinkedResource( "c:\\temp\\logo.gif" );
   logo.ContentId = "companylogo";

   htmlView.LinkedResources.Add(logo);

   mail.AlternateViews.Add(plainView);
   mail.AlternateViews.Add(htmlView);

   var smtp = new SmtpClient("127.0.0.1"); //specify the mail server address
   smtp.Send(mail);
}

1
我知道从某个位置添加图像是可行的,但我想使用应用程序的资源。LinkedResource有一个重载方法,可以使用流而不是文件位置。我尝试使用该方法,但无论是初始图像转流的操作还是将图像流嵌入到LinkedResource中都无法正常工作。 - fluf
4
他询问如何使用 BitmapMemoryStream 而不是直接使用图片文件... - NoWar
注意 - MailMessageSmtpClient 实现了 IDisposable 接口,因此应该在 using 语句中使用或手动释放。 - dav_i
这与楼主的问题无关。 - Dan Cundy
如果我同时添加HTML和纯文本视图,则在接收电子邮件时它总是显示为纯文本模式。如果我只添加HTML,则它总是显示HTML。有没有一种方法可以优先考虑加载HTML视图,如果出现问题,则加载纯文本视图? - Tiger Galo

0

不必将“logo”添加到资源中,我直接将其添加到项目中,并将其设置为“嵌入式资源”。

然后使用System.Reflection.Assembly,我可以将其(我假设是直接)作为流获取:

  var _assembly = Assembly.GetExecutingAssembly();
  var _logoStream = _assembly.GetManifestResourceStream("[Project].[Filename].png");
  var logo = new LinkedResource(_logoStream, "image/png");
  logo.ContentId = "Logo";
  html.LinkedResources.Add(logo);

0

这是我实施的方法:

var htmlBody = "...<img src=\"cid:logo.jpg\" />...";
    
var message = new MailMessage();
message.To.AddRange(mailAddresses);
message.From = fromAddress;

var plaintextView = AlternateView.CreateAlternateViewFromString(plaintextBody, new ContentType(MediaTypeNames.Text.Plain));
plaintextView.ContentType.CharSet = Encoding.UTF8.WebName;
message.AlternateViews.Add(plaintextView);
    
var logoLinkedResource = new LinkedResource(new MemoryStream(Properties.Resources.Logo), MediaTypeNames.Image.Jpeg)
{
    ContentId = "logo.jpg",
    TransferEncoding = TransferEncoding.Base64
};
    
var htmlView = AlternateView.CreateAlternateViewFromString(htmlBody, new ContentType(MediaTypeNames.Text.Html));
htmlView.ContentType.CharSet = Encoding.UTF8.WebName;
htmlView.LinkedResources.Add(logoLinkedResource);
message.AlternateViews.Add(htmlView);
    
message.Subject = subject;

这与上面的一些答案相当相似,但有些不同,并且我花了一些时间来确保细节对我的情况正确。

请注意,电子邮件客户端将使用最后支持的部分/备用视图,因此文本版本应始终首先添加。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接