2011-08-13 31 views
11

Estoy escribiendo un programa que envía correos electrónicos a usuarios con múltiples imágenes (gráficos) incrustadas en el cuerpo del mensaje de correo electrónico (HTML).Cómo incrustar varias imágenes en el cuerpo del correo electrónico usando .NET

Cuando probé la muestra que se encuentra aquí ... que funcionó bien cuando tengo que incrustar una sola imagen http://www.systemnetmail.com/faq/4.4.aspx.

Pero, cuando intenté incrustar varias imágenes usando el siguiente código, ninguna de las imágenes se está incrustando, sino que se envían como archivos adjuntos.

public MailMessage MailMessage(Metric metric, DateTime date) 
{ 
    MailMessage msg = new MailMessage(); 
    msg.From = new MailAddress("[email protected]", "User1"); 
    msg.To.Add(new MailAddress("[email protected]")); 
    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; 
} 

¿Alguna pista que me falta? he comprobado el archivo .htm que también se envía como archivo adjunto con el correo electrónico, y la fuente html se ve de la siguiente manera:

<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> 

Así que el Q es cómo enviar varias imágenes en el cuerpo HTML, no como archivo adjunto.

+1

posible duplicado de [Enviar un correo electrónico con una imagen incrustada en el cuerpo desde C#] (http://stackoverflow.com/questions/1921275/sending-an-email-with-an-image-embedded-in-the- body-from-c) –

Respuesta

6

lo tanto, creo di cuenta de cuál es el problema real es Su en esta línea

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

Como se puede ver, mis dos puntos de vista se especifican como text.html, por lo que el la primera uno es reemplazar la siguiente y así que sólo ver el texto y las imágenes se envían como archivos adjuntos

me hizo el siguiente cambio y funcionó como se esperaba

AlternateView avText = AlternateView.CreateAlternateViewFromString(metric.Name, null, **MediaTypeNames.Text.Plain**); 
AlternateView avImages = AlternateView.CreateAlternateViewFromString(htmlBody, null, MediaTypeNames.Text.Html); 
+0

Tuve el problema exacto. ¡Esto era exactamente lo que estaba buscando! Sin embargo, si alguna vez termino usando más de 2 imágenes, no estoy del todo seguro de cómo crear cada AlternateView. Estoy asumiendo que podré hacer todos ellos, excepto el último como Text.Plain – roshambo

5

Primero, podría tratar de utilizar URI absolutos para imágenes incrustadas. Aquí es ejemplo de RFC-2557:

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

    --boundary-example 
    Content-Type: text/html;charset="US-ASCII" 
    Content-ID: <[email protected]@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-- 

sólo tiene que asignar LinkedResource.ContentLink property en lugar de Content ID.

Segundo, puede incrustar imágenes directamente en su html con the "data" URL scheme.

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

Por cierto, su marcado html no está bien formado. Usted también podría estar interesado en “foreach” vs “ForEach”

+0

¿cómo es que (html) no está bien formado? ¿puedes explicar? – user330612

+0

encontré la solución a mi pblm, como se dice a continuación – user330612

+0

URIs absolutos a imágenes incrustadas resolvió mi problema gracias ... –

1

si tiene las imágenes en línea, lo que significa el envío de un sitio alojado, le sugiero que simplemente haga referencia a esas imágenes simplemente colocando su url en el src.

<!-- using artplastika examples --> 
<IMG SRC="http://www.ietf.cnri.reston.va.us/images/ietflogo.gif" ALT="IETF logo" /> 

la mayoría de los boletines utilizan este método, y creo que es más liviano y puede consumir menos recursos que la incrustación.

esperanza esto ayuda

19

La otra manera de incrustar imágenes en el correo electrónico cuando se utiliza System.Net.Mail es

adjuntar una imagen desde una unidad local al correo electrónico y asignar un contentID a ella y luego utilizar este contentID en la imagen URL.

Esto se puede hacer por:

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>"; 
+0

Por favor, no publique exactamente la misma respuesta a varias preguntas: o no es una buena opción para todos o las preguntas son duplicados que deberían ser marcado/cerrado como tal. – kleopatra

+0

Su método funcionó para mí. Probé recursos vinculados, pero no funcionó. Casi en todas partes que miro, todos parecen tener las imágenes mostradas en sus clientes de correo electrónico utilizando recursos vinculados. ¡Extraño! –

+0

Funciona a la perfección. Realmente no entiendo la necesidad de trabajar con recursos vinculados. Esto es más limpio y más elegante en mi gusto. –

2

Mi alternatie:

En primer lugar, una pequeña extensión:

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

a continuación, obtener los nombres de imagen de la carpeta:

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

luego reemplazando i nombres de magos por 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); 
    } 

donde el cuerpo - es cuerpo HTML, y por ejemplo, <img src="Images/logo_shadow.png" alt="" style="width: 100%;" /> será reemplazado por <img src="cid:logo_shadow.png" alt="" style="width: 100%;" />

luego última acción: la adición de imágenes itselfs al correo:

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; 
    } 
1
 AlternateView avHtml = AlternateView.CreateAlternateViewFromString(body, null, MediaTypeNames.Text.Html); 
     LinkedResource inline = new LinkedResource(System.Web.HttpContext.Current.Server.MapPath("~/Images/e1.jpg"), MediaTypeNames.Image.Jpeg); 
     inline.ContentId = "1"; 
     inline.TransferEncoding = System.Net.Mime.TransferEncoding.Base64; 
     avHtml.LinkedResources.Add(inline); 

     LinkedResource inline1 = new LinkedResource(System.Web.HttpContext.Current.Server.MapPath("~/CImages/2.jpg"), MediaTypeNames.Image.Jpeg); 
     inline1.ContentId = "2"; 
     inline1.TransferEncoding = System.Net.Mime.TransferEncoding.Base64; 
     avHtml.LinkedResources.Add(inline1); 

     LinkedResource inline2 = new LinkedResource(System.Web.HttpContext.Current.Server.MapPath("~/Images/3.jpg"), MediaTypeNames.Image.Jpeg); 
     inline2.ContentId = "3"; 
     inline2.TransferEncoding = System.Net.Mime.TransferEncoding.Base64; 
     avHtml.LinkedResources.Add(inline2); 

     LinkedResource inline3 = new LinkedResource(System.Web.HttpContext.Current.Server.MapPath("~/Content/Images/4.jpg"), MediaTypeNames.Image.Jpeg); 
     inline3.ContentId = "4"; 
     inline3.TransferEncoding = System.Net.Mime.TransferEncoding.Base64; 
     avHtml.LinkedResources.Add(inline3); 

     MailMessage mail = new MailMessage(); 
     mail.AlternateViews.Add(avHtml); 

HTML:

 <img src="cid:1" alt="" /> 
     <img src="cid:2" alt="" /> 
     <img src="cid:3" alt="" /` 
     <img src="cid:4" alt="" /> 
Cuestiones relacionadas