如何使用.NET在电子邮件正文中嵌入多个图像

use*_*612 13 c# image system.net.mail

我正在编写一个程序,向用户发送电子邮件,其中包含嵌入电子邮件正文(HTML)中的多个图像(图表).

当我尝试这里的样本时......当我只需要嵌入一个图像http://www.systemnetmail.com/faq/4.4.aspx时效果很好 .

但是,当我尝试使用以下代码嵌入多个图像时,没有嵌入任何图像,而是将它们作为附件发送.

public MailMessage MailMessage(Metric metric, DateTime date)
{
    MailMessage msg = new MailMessage();
    msg.From = new MailAddress("test@gmail.com", "User1");
    msg.To.Add(new MailAddress("test@gmail.com"));
    msg.Subject = "Trend for metric: " + metric.Name;
    msg.IsBodyHtml = true;

    // Generate the charts for the given metric
    var charts = this.GenerateCharts(metric, date);
    int i = 0;
    string htmlBody = "<html><body>";
    List<LinkedResource> resources = new List<LinkedResource>();
    foreach (var chart in charts)
    {
        string imageTag = string.Format("<img src=cid:chart{0} /><br>", i);
        htmlBody += imageTag;
        LinkedResource graph = new LinkedResource(chart.Value, "image/jpeg");
        graph.ContentId = "chart" + i;
        resources.Add(graph);
        i++;
    }

    htmlBody += "</body></html>";

    // Alternate view for embedded images
    AlternateView avText = AlternateView.CreateAlternateViewFromString(metric.Name, null, MediaTypeNames.Text.Html);
    AlternateView avImages = AlternateView.CreateAlternateViewFromString(htmlBody, null, MediaTypeNames.Text.Html);

    // Add all the images as linked resources
    resources.ForEach(x => avImages.LinkedResources.Add(x));

    // Add the views for image
    msg.AlternateViews.Add(avText);
    msg.AlternateViews.Add(avImages);


    return msg;
}
Run Code Online (Sandbox Code Playgroud)

我缺少的任何线索?我检查了.htm文件,它也作为电子邮件附件发送,html源代码如下:

<html>><body><img src=cid:chart0 /><br><img src=cid:chart1 /><br><img src=cid:chart2/><br><img src=cid:chart3 /><br><img src=cid:chart4 /><br></body></html>
Run Code Online (Sandbox Code Playgroud)

所以Q是如何在html体内发送多个图像,而不是附件.

小智 20

使用时将图像嵌入电子邮件的另一种方法System.Net.Mail

将图像从本地驱动器附加到电子邮件并分配contentID给它,然后contentID在图像URL中使用它.

这可以通过以下方式完成:

var contentID = "Image";
var inlineLogo = new Attachment(@"C:\Desktop\Image.jpg");
inlineLogo.ContentId = contentID;
inlineLogo.ContentDisposition.Inline = true;
inlineLogo.ContentDisposition.DispositionType = DispositionTypeNames.Inline;

msg.IsBodyHtml = true;
msg.Attachments.Add(inlineLogo);
msg.Body = "<htm><body> <img src=\"cid:" + contentID + "\"> </body></html>";
Run Code Online (Sandbox Code Playgroud)

  • 你的方法对我有用。我试过链接资源,但没有用。几乎在我所看到的任何地方,每个人似乎都使用链接资源在他们的电子邮件客户端中显示了图像。奇怪的! (2认同)
  • 完美运行。我真的不明白使用链接资源的必要性。这在我的口味中更干净,更优雅。 (2认同)

use*_*612 6

所以,我想在这一行中找出实际问题是什么

// Alternate view for embedded images
    AlternateView avText = AlternateView.CreateAlternateViewFromString(metric.Name, null, MediaTypeNames.Text.Html);
    AlternateView avImages = AlternateView.CreateAlternateViewFromString(htmlBody, null, MediaTypeNames.Text.Html);
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,我的两个视图都指定为Text.Html,因此第一个视图将覆盖下一个视图,因此我只看到文本和图像作为附件发送

我做了以下更改,它按预期工作

AlternateView avText = AlternateView.CreateAlternateViewFromString(metric.Name, null, **MediaTypeNames.Text.Plain**);
AlternateView avImages = AlternateView.CreateAlternateViewFromString(htmlBody, null, MediaTypeNames.Text.Html);
Run Code Online (Sandbox Code Playgroud)


art*_*ika 5

首先,您可以尝试使用绝对URI来嵌入图像.以下是RFC-2557的示例:

  From: foo1@bar.net
  To: foo2@bar.net
  Subject: A simple example
  Mime-Version: 1.0
  Content-Type: multipart/related; boundary="boundary-example";
          type="text/html"; start="<foo3@foo1@bar.net>"

  --boundary-example
  Content-Type: text/html;charset="US-ASCII"
  Content-ID: <foo3@foo1@bar.net>

  ... text of the HTML document, which might contain a URI
  referencing a resource in another body part, for example
  through a statement such as:
  <IMG SRC="http://www.ietf.cnri.reston.va.us/images/ietflogo.gif" ALT="IETF logo">

  --boundary-example
  Content-Location:
     http://www.ietf.cnri.reston.va.us/images/ietflogo.gif
  Content-Type: IMAGE/GIF
  Content-Transfer-Encoding: BASE64

  R0lGODlhGAGgAPEAAP/////ZRaCgoAAAACH+PUNvcHlyaWdodCAoQykgMTk5
  NSBJRVRGLiBVbmF1dGhvcml6ZWQgZHVwbGljYXRpb24gcHJvaGliaXRlZC4A
  etc...

  --boundary-example--
Run Code Online (Sandbox Code Playgroud)

您只需要分配LinkedResource.ContentLink属性而不是ContentId.

其次,您可以使用"数据"URL方案将图像直接嵌入到html中.

    <IMG
    SRC="data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAw
    AAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUUlvONmOZtfzgFz
    ByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSp
    a/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQZXZeYGejmJl
    ZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwvKOzrcd3iq9uis
    F81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PH
    hhx4dbgYKAAA7"
    ALT="Larry">
Run Code Online (Sandbox Code Playgroud)

顺便说一下,你的html标记格式不正确.你可能也对"foreach"vs"ForEach"感兴趣


Ale*_*kiy 5

我的替代者:

首先,稍微扩展一下:

public static class RegexExtensions
{
    public static string GetPattern(this IEnumerable<string> valuesToSearch)
    {
        return string.Format("({0})", string.Join("|", valuesToSearch));
    }
}
Run Code Online (Sandbox Code Playgroud)

然后从文件夹中获取图像名称:

    private string[] GetFullNamesOfImages()
    {
        string images = Path.Combine(_directoryName, "Images");
        if (!Directory.Exists(images))
            return new string[0];
        return Directory.GetFiles(images);
    }
Run Code Online (Sandbox Code Playgroud)

然后用 cid 替换图像名称:

    private string InsertImages(string body)
    {
        var images = GetFullNamesOfImages().Select(Path.GetFileName).ToArray();
        return Regex.Replace(body, "(Images/)?" + images.GetPattern(), "cid:$2", RegexOptions.IgnoreCase | RegexOptions.Compiled);
    }
Run Code Online (Sandbox Code Playgroud)

其中 body - 是 HTML 正文,例如,<img src="Images/logo_shadow.png" alt="" style="width: 100%;" />将替换为<img src="cid:logo_shadow.png" alt="" style="width: 100%;" />

然后最后一个操作:将图像本身添加到邮件中:

    private MailMessage CreateMail(SmtpClient smtp, string toAddress, string body)
    {
        var images = GetFullNamesOfImages();

        string decodedBody = WebUtility.HtmlDecode(body);
        var text = AlternateView.CreateAlternateViewFromString(decodedBody, null, MediaTypeNames.Text.Plain);
        var html = AlternateView.CreateAlternateViewFromString(body, null, MediaTypeNames.Text.Html);
        foreach (var image in images)
        {
            html.LinkedResources.Add(new LinkedResource(image, new ContentType("image/png"))
                                     {
                                         ContentId = Path.GetFileName(image)
                                     });
        }


        var credentials = (NetworkCredential) smtp.Credentials;

        var message = new MailMessage(new MailAddress(credentials.UserName), new MailAddress(toAddress))
                      {
                          Subject = "Some subj",
                          Body = decodedBody
                      };
        message.AlternateViews.Add(text);
        message.AlternateViews.Add(html);
        return message;
    }
Run Code Online (Sandbox Code Playgroud)