GMail not showing inline-images (cid) i'm sending with System.Net.Mail

18,999

Solution 1

The inline-image is ignored in GMail webinterface when added as attachment. When adding the image as alternate view it gets ignored by Outlook.

To add an inline-image compatible to GMail webinterface and Outlook (and iPhone mail client) you have to add it as LinkedResource.

The example code in the question must be fixed like this:

SmtpClient client = new SmtpClient("real.server.on.the.internet");
MailMessage mail = new MailMessage("Flattiverse <[email protected]>", "Ghostie <[email protected]>");
mail.BodyEncoding = System.Text.Encoding.UTF8;
mail.SubjectEncoding = System.Text.Encoding.UTF8;

LinkedResource image = new LinkedResource("test.png", "image/png");
image.ContentId = "[email protected]";
image.TransferEncoding = System.Net.Mime.TransferEncoding.Base64;
image.ContentType.Name = "[email protected]";
image.ContentLink = new Uri("cid:[email protected]");

AlternateView plainView = AlternateView.CreateAlternateViewFromString("Please view as HTML-Mail.", System.Text.Encoding.UTF8, "text/plain");
plainView.TransferEncoding = System.Net.Mime.TransferEncoding.QuotedPrintable;

AlternateView htmlView = AlternateView.CreateAlternateViewFromString("Image there?<br /><img src=\"cid:[email protected]\" /><br />Hope so!", System.Text.Encoding.UTF8, "text/html");
htmlView.LinkedResources.Add(image);
htmlView.TransferEncoding = System.Net.Mime.TransferEncoding.QuotedPrintable;
mail.AlternateViews.Add(plainView);
mail.AlternateViews.Add(htmlView);

mail.Subject = "15";

client.UseDefaultCredentials = false;
client.Credentials = new System.Net.NetworkCredential("working_username", "working_password");
client.Send(mail);

Solution 2

I had the same Problem with Pyhon (Django). Solved it by just adding the X-Attachment-Id header:

img.add_header('Content-ID', '<filename.png>')
img.add_header('X-Attachment-Id', 'filename.png')
img.add_header('Content-Disposition', 'inline', filename='filename.png')
message.attach(img)

Hope this helps someone :-)

Solution 3

I had the same issue (in Java, will be same for c#). Resolved by adding contentId between the “<” and “>”

enter image description here

This one is working on Gmail,yahoo and Outlook.

Solution 4

Add it as LinkedResource.

I have a template called Confirm_Account_RegistrationInd.html

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>Bienvenido Email de  {6}</title>
</head>

<body>
    <table width="100%" border="0" cellspacing="0" cellpadding="0">
        <tr>
            <td align="center" valign="top" bgcolor="#fff" style="background-color:lightgray;">
                <br>
                <br>
                <table width="600" border="0" cellspacing="0" cellpadding="0" >
                    <tr>
                        <td height="70" align="left" valign="middle"></td>
                    </tr>
                    <tr>
                        <td align="left" valign="top" bgcolor="#564319" style="background-color:#007ebd; font-family:Arial, Helvetica, sans-serif; padding:10px;">
                            <table>
                                <tr>
                                    <td>
                                        "<img id="logo" src="miimg_id" alt="logo" style="height: 60px; border: 3px solid #007ebd; border-radius: 43px;" />";
                                    </td>
                                    <td>
                                        <div style="font-size:36px; color:#ffffff;">
                                            <b>{0}</b>
                                        </div>
                                        <div style="font-size:13px; color:lightcyan;">
                                            <b>{1} : {6}</b>
                                        </div>
                                    </td>
                                    
                                </tr>
                        </table>
                        </td>
                    </tr>
                    <tr>
                        <td align="left" valign="top" bgcolor="#ffffff" style="background-color:#ffffff;">
                            <table width="100%" border="0" cellspacing="0" cellpadding="0">
                                <tr>
                                    <td align="center" valign="middle" style="padding:10px; color:#564319; font-size:28px; font-family:Georgia, 'Times New Roman', Times, serif;">
                                        ¡Felicitaciones! <small>Estás Registrado.</small>
                                    </td>
                                </tr>
                            </table>
                            <table width="95%" border="0" align="center" cellpadding="0" cellspacing="0">
                                
                                <tr>
                                    <td width="100%" style="color:darkslategrey; font-family:Arial, Helvetica, sans-serif; padding:10px;">
                                        <div style="font-size:16px;">
                                            Apreciad@ {2},
                                        </div>
                                        <div style="font-size:12px;text-align: justify;">
                                            Ha sido creada una cuenta en el sitio.
                                            Todo lo que necesitas es hacer clic en el botón en la parte de abajo (Te tomará solamente un momento)
                                            Este correo es para la verificación de la propiedad del correo elctrónico.
                                            <hr>
                                            <center>

                                                <button type="button" title="Confirmar cuenta" style="background: darkgoldenrod">
                                                    <a href="{5}" style="font-size:22px;  padding: 10px; color: #ffffff">
                                                        Confirmar correo ahora
                                                    </a>
                                                </button>

                                            </center>
                                            <hr>
                                        </div>
                                    </td>
                                </tr>
                            </table>
                            
                            <table width="100%" border="0" align="center" cellpadding="0" cellspacing="0" style="margin-bottom:15px;">
                                <tr>
                                    <td align="left" valign="middle" style="padding:15px; font-family:Arial, Helvetica, sans-serif;">
                                        <div style="font-size:20px; color:#564319;">
                                            <b>Por favor manten tus credenciales seguras, para usarlas en el futuro. </b>
                                        </div>
                                        <div style="font-size:16px; color:#525252;">
                                            <b>Correo         :</b> {3}
                                            <br />
                                            <b>Nombre de usuario :</b> {3}
                                            <br />
                                            {7}
                                            <br />
                                        </div>
                                    </td>
                                </tr>
                            </table>
                            <table width="100%" border="0" cellspacing="0" cellpadding="0">
                                <tr>
                                    <td align="center" valign="middle" style="padding:15px; background-color:#007ebd; font-family:Arial, Helvetica, sans-serif;">

                                        <div style="font-size:20px; color:#fff;">
                                            <b>¡Actualiza tus contraseñas continuamente!</b>
                                        </div>
                                        <br>
                                        <div style="font-size:13px; color:aliceblue;">

                                            <br>


                                        </div>
                                    </td>
                                </tr>
                            </table>
                           
                        </td>
                    </tr>
                    
                </table>
                <br>
                <br>
            </td>
        </tr>
    </table>
</body>
</html>

The image that i want to show:

"<img id="logo" src="miimg_id" alt="logo" style="height: 60px; border: 3px solid #007ebd; border-radius: 43px;" />";

as you can show the src attribute has a value miimg_id

and into the view i have values to fill {}

I have my method where i will read my view as string, after get data to fill the values, called ReSendEmailAsync

[HttpPost]
        public async Task<IActionResult> ReSendEmailAsync([FromBody] string id)
        {
            string returnUrl = null;
            returnUrl = returnUrl ?? Url.Content("~/");

            string empleadoNombre = "";
            string attach = "";
            string logoName = "logo_dif.png";


            var user = await _unitOfWork.ApplicationUser.GetFirstOrDefaultAsync(u => u.Id == int.Parse(id), includeProperties: "Empleado");

            if (user == null)
            {
                return Json(new { success = false, message = "Usuario Email" });
            }
            if (user.EmailConfirmed)
            {
                return Json(new { success = true, message = "Cuenta ya fue confirmada" });
            }

            try
            {
                empleadoNombre = user.Empleado.Nombre;
            }
            catch (Exception e)
            {

            }

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user).ConfigureAwait(true);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);

            //Customizde email
            var PathToFile = _webHostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString()
                + "Templates" + Path.DirectorySeparatorChar.ToString()
                + "EmailTemplates" + Path.DirectorySeparatorChar.ToString()
                + "Confirm_Account_RegistrationInd.html";

            var subject = "Confirmar Registro de cuenta";
            string HtmlBody = "";

            using (StreamReader streamReader = System.IO.File.OpenText(PathToFile))
            {
                HtmlBody = streamReader.ReadToEnd();
            }

        //{0} Subject
        //{1} DateTime
        //{2} Name
        //{3} Email
        //{4} Messaje
        //{5} CallBack
        //{6} AppName
        //{7} Pass

                // logo as attach
                var PathToImage = _webHostEnvironment.WebRootPath + Path.DirectorySeparatorChar.ToString()
                + "Templates" + Path.DirectorySeparatorChar.ToString()
                + "EmailTemplates" + Path.DirectorySeparatorChar.ToString()
                + logoName;

                attach = PathToImage;


            string message = $"Por favor confirme su cuenta <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>Clic Aquí</a>.";
            string messageBody = string.Format(HtmlBody,
                subject,
                String.Format("{0:dddd, d MMMM yyyy}", DateTime.Now),
                empleadoNombre,
                user.Email,
                message,
                callbackUrl,
                "Indicadores",
                ""
             );

            try
            {
                MailRequest mailRequest = new MailRequest();

                mailRequest.Body = messageBody;
                mailRequest.ToEmail = user.Email;
                mailRequest.Subject = "Confirmar su correo";
                mailRequest.Attachments = new List<MailAttachment> 
                { new MailAttachment{
                    Name = logoName,
                    Path = attach
                } };

                await _mailService.SendEmailAsync(mailRequest);
            }
            catch(Exception e)
            {
                return Json(new { success = false, message = "Al enviar email" });
            }

            return Json(new { success = true, message = "Operación exitosa" });
        }

In my class MailService

Main methed is SendEmailAsync where i pass the values to the MailMessage object

but i have another method called Mail_Body that return a AlternateView object

public class MailService : IMailService
    {
        private readonly MailSettings _mailSettings;
        public MailService(IOptions<MailSettings> mailSettings)
        {
            _mailSettings = mailSettings.Value;
        }

        public async Task SendEmailAsync(MailRequest mailRequest)
        {
            MailMessage message = new MailMessage();
            SmtpClient smtp = new SmtpClient();
            message.From = new MailAddress(_mailSettings.UserName);
            message.To.Add(new MailAddress(mailRequest.ToEmail));
            message.Subject = mailRequest.Subject;
            message.BodyEncoding = System.Text.Encoding.UTF8;
            message.SubjectEncoding = System.Text.Encoding.UTF8;
            if (mailRequest.Attachments != null)
            {
                //int i = 0;
                foreach (var attachmentStr in mailRequest.Attachments)
                {
                    message.AlternateViews.Add(Mail_Body(mailRequest.Body, attachmentStr.Path, attachmentStr.Name));

                }
            }
            message.IsBodyHtml = true;
            smtp.Port = _mailSettings.Port;
            smtp.Host = _mailSettings.Host;
            smtp.EnableSsl = _mailSettings.EnableSSL;
            smtp.UseDefaultCredentials = false;
            smtp.Credentials = new NetworkCredential(_mailSettings.UserName, _mailSettings.Password);
            smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
            await smtp.SendMailAsync(message);
        }

        private AlternateView Mail_Body(string strr, string path, string contentId)
        {

            LinkedResource Img = new LinkedResource(path, "image/png");
            Img.ContentId = "logo_img";

            strr = strr.Replace("\"miimg_id\"", "cid:logo_img");

            AlternateView AV =
            AlternateView.CreateAlternateViewFromString(strr, null, MediaTypeNames.Text.Html);
            AV.LinkedResources.Add(Img);
            return AV;
        }
    }

the logo image is called logo_dif.png and is located in

enter image description here

finally the result in gmail:

enter image description here

Share:
18,999
Matthias
Author by

Matthias

According to my calculations this problem doesn't exist.

Updated on June 04, 2022

Comments

  • Matthias
    Matthias almost 2 years

    When I send an email via outlook or gmail to a gmail email address I can add inline-images which are directly shown in the gmail webinterface:

    GMail webinterface with working inline image

    Relevant raw mail-header and raw body parts of the working email:

    --089e0158b6909948880520cef593
    Content-Type: text/html; charset=UTF-8
    Content-Transfer-Encoding: quoted-printable
    
    <div dir=3D"ltr">Image there?<div><img src=3D"cid:ii_if3zqhar0_15014363be0a=
    41b2" width=3D"10" height=3D"3"><br>=E2=80=8BHope so!<br></div></div>
    
    --089e0158b6909948880520cef593--
    --089e0158b69099488c0520cef594
    Content-Type: image/png; name="test.png"
    Content-Disposition: inline; filename="test.png"
    Content-Transfer-Encoding: base64
    Content-ID: <ii_if3zqhar0_15014363be0a41b2>
    X-Attachment-Id: ii_if3zqhar0_15014363be0a41b2
    
    iVBORw0KGgoAAAANSUhEUgAAAAoAAAADCAIAAAAlXwkiAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJ
    bWFnZVJlYWR5ccllPAAAADFJREFUeNpi+A8BDCf/wwDD/1VIbBABIudDmAchokwgag9QAiwHVcsM
    Z/5fCdYJEGAAuthJ+AVi5KgAAAAASUVORK5CYII=
    --089e0158b69099488c0520cef594--
    

    Full working raw email: Working raw-email.

    However, when I send such an email via System.Net.Mail from .NET it is not working in the gmail webinterface but any other email client (outlook, iphone, etc.):

    GMail webinterface with not working inline image

    Relevant raw mail-header and raw-body parts of non-working email:

    ----boundary_3_6a0761ee-57e2-4bdd-b1f1-7302b3c8a7a1
    Content-Type: text/html; charset=utf-8
    Content-Transfer-Encoding: quoted-printable
    
    Image there?<br /><img src=3D"cid:[email protected]" /><=
    br />Hope so!
    ----boundary_3_6a0761ee-57e2-4bdd-b1f1-7302b3c8a7a1--
    
    ----boundary_5_979e00c0-3fb9-46a0-b25c-1cee82cc15eb
    Content-Type: image/png; name=test.png
    Content-Transfer-Encoding: base64
    Content-Disposition: inline; filename=test.png
    Content-ID: <[email protected]>
    
    iVBORw0KGgoAAAANSUhEUgAAAAoAAAADCAIAAAAlXwkiAAAAGXRFWHRTb2Z0d2FyZQBB
    ZG9iZSBJbWFnZVJlYWR5ccllPAAAADFJREFUeNpi+A8BDCf/wwDD/1VIbBABIudDmAch
    okwgag9QAiwHVcsMZ/5fCdYJEGAAuthJ+AVi5KgAAAAASUVORK5CYII=
    ----boundary_5_979e00c0-3fb9-46a0-b25c-1cee82cc15eb--
    

    Full non-working raw email: Nonworking raw-email.

    This is my code to send inline-images:

    SmtpClient client = new SmtpClient("real.server.on.the.internet");
    MailMessage mail = new MailMessage("Flattiverse <[email protected]>", "Ghostie <[email protected]>");
    mail.BodyEncoding = System.Text.Encoding.UTF8;
    mail.SubjectEncoding = System.Text.Encoding.UTF8;
    
    AlternateView plainView = AlternateView.CreateAlternateViewFromString("Please view as HTML-Mail.", System.Text.Encoding.UTF8, "text/plain");
    plainView.TransferEncoding = System.Net.Mime.TransferEncoding.QuotedPrintable;
    
    AlternateView htmlView = AlternateView.CreateAlternateViewFromString("Image there?<br /><img src=\"cid:[email protected]\" /><br />Hope so!", System.Text.Encoding.UTF8, "text/html");
    htmlView.TransferEncoding = System.Net.Mime.TransferEncoding.QuotedPrintable;
    mail.AlternateViews.Add(plainView);
    mail.AlternateViews.Add(htmlView);
    
    mail.Subject = "7";
    
    Attachment attachment = new Attachment("test.png", "image/png");
    attachment.ContentId = "[email protected]";
    attachment.ContentDisposition.Inline = true;
    attachment.ContentDisposition.DispositionType = "inline; filename=test.png";
    mail.Attachments.Add(attachment);
    
    client.UseDefaultCredentials = false;
    client.Credentials = new System.Net.NetworkCredential("working_username", "working_password");
    client.Send(mail);
    

    I also tried cid in GMail format (eg. ii_012345678_9abcdef0123456789) and many other things stated in other related questions. (Using ' instead of " in mail body, etc.)

    Question: What am I doing wrong that GMail doesn't display my inline-images? How do I need to change my code? Maybe what I want can't be achieved with System.Net.Mail?