44

I'm sending emails to my members and it looks like Gmail is blocking the images I place in the email. These are embedded as a base 64 encoded string in an img tag. I've looked at multiple threads online about Gmail not sending images but haven't found anything that helps. Here are some of the things I've tried so far. 1. enabled external images in Gmail (through the settings icon) 2. reduced the size of the images to under 8000 bytes (Outlook.com wouldn't send images ~ 15000 bytes)

I receive the images just fine if I send to an outlook.com email address, but in Gmail the src of the img tag is empty, and no images show up in the email. I'm using https://putsmail.com to test/send my emails, so I know the issue isn't a problem with SendGrid (my email sending service) or my application.

Here is one of my templates below. I'm using an email template from litmuss. Everything below is basically default except the extra info I've added like the images and some extra text in the email body.

Here is a jsfiddle with a complete template with image data that can be copied right into putsmail and be sent to test! Any help or info as to why Gmail doesn't send the images would be great!

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <style type="text/css">
        /* FONTS */
        @@media screen {
            @@font-face {
                font-family: 'Lato';
                font-style: normal;
                font-weight: 400;
                src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v11/qIIYRU-oROkIk8vfvxw6QvesZW2xOQ-xsNqO47m55DA.woff) format('woff');
            }

            @@font-face {
                font-family: 'Lato';
                font-style: normal;
                font-weight: 700;
                src: local('Lato Bold'), local('Lato-Bold'), url(https://fonts.gstatic.com/s/lato/v11/qdgUG4U09HnJwhYI-uK18wLUuEpTyoUstqEm5AMlJo4.woff) format('woff');
            }

            @@font-face {
                font-family: 'Lato';
                font-style: italic;
                font-weight: 400;
                src: local('Lato Italic'), local('Lato-Italic'), url(https://fonts.gstatic.com/s/lato/v11/RYyZNoeFgb0l7W3Vu1aSWOvvDin1pK8aKteLpeZ5c0A.woff) format('woff');
            }

            @@font-face {
                font-family: 'Lato';
                font-style: italic;
                font-weight: 700;
                src: local('Lato Bold Italic'), local('Lato-BoldItalic'), url(https://fonts.gstatic.com/s/lato/v11/HkF_qI1x_noxlxhrhMQYELO3LdcAZYWl9Si6vvxL-qU.woff) format('woff');
            }
        }

        /* CLIENT-SPECIFIC STYLES */
        body, table, td, a {
            -webkit-text-size-adjust: 100%;
            -ms-text-size-adjust: 100%;
        }

        table, td {
            mso-table-lspace: 0pt;
            mso-table-rspace: 0pt;
        }

        img {
            -ms-interpolation-mode: bicubic;
        }

        /* RESET STYLES */
        img {
            border: 0;
            height: auto;
            line-height: 100%;
            outline: none;
            text-decoration: none;
        }

        table {
            border-collapse: collapse !important;
        }

        body {
            height: 100% !important;
            margin: 0 !important;
            padding: 0 !important;
            width: 100% !important;
        }

        /* iOS BLUE LINKS */
        a[x-apple-data-detectors] {
            color: inherit !important;
            text-decoration: none !important;
            font-size: inherit !important;
            font-family: inherit !important;
            font-weight: inherit !important;
            line-height: inherit !important;
        }

        /* MOBILE STYLES */
        @@media screen and (max-width:600px) {
            h1 {
                font-size: 32px !important;
                line-height: 32px !important;
            }
        }

        /* ANDROID CENTER FIX */
        div[style*="margin: 16px 0;"] {
            margin: 0 !important;
        }
    </style>
</head>
<body style="background-color: #f4f4f4; margin: 0 !important; padding: 0 !important;">

    <!-- HIDDEN PREHEADER TEXT -->
    <div style="display: none; font-size: 1px; color: #fefefe; line-height: 1px; font-family: 'Lato', Helvetica, Arial, sans-serif; max-height: 0px; max-width: 0px; opacity: 0; overflow: hidden;">
        We're thrilled you created a YogaBandy event! Get ready for members to register.
    </div>

    <table border="0" cellpadding="0" cellspacing="0" width="100%">
        <!-- LOGO -->
        <tr>
            <td bgcolor="#16749F" align="center">
                <!--[if (gte mso 9)|(IE)]>
                <table align="center" border="0" cellspacing="0" cellpadding="0" width="600">
                <tr>
                <td align="center" valign="top" width="600">
                <![endif]-->
                <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
                    <tr>
                        <td align="center" valign="top" style="padding: 40px 10px 40px 10px;">
                            <a href="https://YogaBandy.com" target="_blank">
                                <img alt="Logo" src="http://litmuswww.s3.amazonaws.com/community/template-gallery/ceej/logo.png" width="40" height="40" style="display: block; width: 40px; max-width: 40px; min-width: 40px; font-family: 'Lato', Helvetica, Arial, sans-serif; color: #ffffff; font-size: 18px;" border="0">
                            </a>
                        </td>
                    </tr>
                </table>
                <!--[if (gte mso 9)|(IE)]>
                </td>
                </tr>
                </table>
                <![endif]-->
            </td>
        </tr>
        <!-- HERO -->
        <tr>
            <td bgcolor="#16749F" align="center" style="padding: 0px 10px 0px 10px;">
                <!--[if (gte mso 9)|(IE)]>
                <table align="center" border="0" cellspacing="0" cellpadding="0" width="600">
                <tr>
                <td align="center" valign="top" width="600">
                <![endif]-->
                <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
                    <tr>
                        <td bgcolor="#ffffff" align="center" valign="top" style="padding: 40px 20px 20px 20px; border-radius: 4px 4px 0px 0px; color: #111111; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 48px; font-weight: 400; letter-spacing: 4px; line-height: 48px;">
                            <h2 style="font-size: 48px; font-weight: 400; margin: 0;">Event Created</h2>
                        </td>
                    </tr>
                </table>
                <!--[if (gte mso 9)|(IE)]>
                </td>
                </tr>
                </table>
                <![endif]-->
            </td>
        </tr>
        <!-- COPY BLOCK -->
        <tr>
            <td bgcolor="#f4f4f4" align="center" style="padding: 0px 10px 0px 10px;">
                <!--[if (gte mso 9)|(IE)]>
                <table align="center" border="0" cellspacing="0" cellpadding="0" width="600">
                <tr>
                <td align="center" valign="top" width="600">
                <![endif]-->
                <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
                    <!-- COPY -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">We're excited you have created an event. Here are some of the details below.</p>
                        </td>
                    </tr>
                    <!-- Host Space -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">
                                <a href="https://www.YogaBandy.com/Space/Public/@Model.SpaceId" target="_blank" class="thumbnail" style="margin-bottom: 0px;">
                                    <img alt="SpaceImage" title="Space Image" style="display: block" width="225" height="126" src="data:image/jpg;base64,@Raw(Model.SpaceThumbnail)" />
                                    <div class="caption">
                                        @Model.SpaceName
                                    </div>
                                </a>
                            </p>
                        </td>
                    </tr>
                    <!-- Host Image -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">
                                <a href="https://www.YogaBandy.com/Profile/Public/@Model.HostId" target="_blank" class="thumbnail" style="margin-bottom: 0px;">
                                    <img alt="HostImage" title="Host Image" style="display: block" width="225" height="225" src="data:image/jpg;base64,@Raw(Model.HostThumbnail)" />
                                    <div class="caption">
                                        @Model.HostName
                                    </div>
                                </a>
                            </p>
                        </td>
                    </tr>
                    <!-- DATE -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">@Model.Date.ToLongDateString()</p>
                        </td>
                    </tr>
                    <!-- TIME -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">
                                <div>Time: @Model.Date.ToShortTimeString()</div>
                            </p>
                        </td>
                    </tr>
                    <!-- Location -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">@Model.Location</p>
                        </td>
                    </tr>
                    <!-- DURATION -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">@Model.Duration</p>
                        </td>
                    </tr>
                    <!-- STYLE -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 20px 30px 40px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">@Model.Style</p>
                        </td>
                    </tr>
                    <!-- BULLETPROOF BUTTON -->
                    <tr>
                        <td bgcolor="#ffffff" align="left">
                            <table width="100%" border="0" cellspacing="0" cellpadding="0">
                                <tr>
                                    <td bgcolor="#ffffff" align="center" style="padding: 20px 30px 60px 30px;">
                                        <table border="0" cellspacing="0" cellpadding="0">
                                            <tr>
                                                <td align="center" style="border-radius: 3px;" bgcolor="#16749F"><a href="" target="_blank" style="font-size: 20px; font-family: Helvetica, Arial, sans-serif; color: #ffffff; text-decoration: none; color: #ffffff; text-decoration: none; padding: 15px 25px; border-radius: 2px; border: 1px solid #16749F; display: inline-block;">Add To Calendar</a></td>
                                            </tr>
                                        </table>
                                    </td>
                                </tr>
                            </table>
                        </td>
                    </tr>
                    
                    
                    <!-- COPY -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 0px 30px 20px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">If you have any questions, just send an email to the support address—we're always happy to help out.</p>
                        </td>
                    </tr>
                    <!-- COPY -->
                    <tr>
                        <td bgcolor="#ffffff" align="left" style="padding: 0px 30px 40px 30px; border-radius: 0px 0px 4px 4px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <p style="margin: 0;">Cheers,<br>The YogaBandy Team</p>
                        </td>
                    </tr>
                </table>
                <!--[if (gte mso 9)|(IE)]>
                </td>
                </tr>
                </table>
                <![endif]-->
            </td>
        </tr>
        <!-- SUPPORT CALLOUT -->
        <tr>
            <td bgcolor="#f4f4f4" align="center" style="padding: 30px 10px 0px 10px;">
                <!--[if (gte mso 9)|(IE)]>
                <table align="center" border="0" cellspacing="0" cellpadding="0" width="600">
                <tr>
                <td align="center" valign="top" width="600">
                <![endif]-->
                <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
                    <!-- HEADLINE -->
                    <tr>
                        <td bgcolor="#157b9d" align="center" style="padding: 30px 30px 30px 30px; border-radius: 4px 4px 4px 4px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 400; line-height: 25px;">
                            <h2 style="font-size: 20px; font-weight: 400; color: #111111; margin: 0;">Need more help?</h2>
                            <p style="margin: 0;"><a href="https://YogaBandy/Contact.com" target="_blank" style="color: #FFFFFF;">We&rsquo;re here, ready to help</a></p>
                        </td>
                    </tr>
                </table>
                <!--[if (gte mso 9)|(IE)]>
                </td>
                </tr>
                </table>
                <![endif]-->
            </td>
        </tr>
        <!-- FOOTER -->
        <tr>
            <td bgcolor="#f4f4f4" align="center" style="padding: 0px 10px 0px 10px;">
                <!--[if (gte mso 9)|(IE)]>
                <table align="center" border="0" cellspacing="0" cellpadding="0" width="600">
                <tr>
                <td align="center" valign="top" width="600">
                <![endif]-->
                <table border="0" cellpadding="0" cellspacing="0" width="100%" style="max-width: 600px;">
                    <!-- NAVIGATION -->
                    <!-- PERMISSION REMINDER -->
                    <tr>
                        <td bgcolor="#f4f4f4" align="left" style="padding: 0px 30px 30px 30px; color: #666666; font-family: 'Lato', Helvetica, Arial, sans-serif; font-size: 14px; font-weight: 400; line-height: 18px;">
                            <p style="margin: 0;">You received this email because you just created a YogaBandy event. If it looks weird, <a href="https://YogaBandy.com" target="_blank" style="color: #111111; font-weight: 700;">view it in your browser</a>.</p>
                        </td>
                    </tr>
                    <!-- UNSUBSCRIBE -->
                    <!-- ADDRESS -->

                </table>
                <!--[if (gte mso 9)|(IE)]>
                </td>
                </tr>
                </table>
                <![endif]-->
            </td>
        </tr>
    </table>

</body>
</html>
chuckd
  • 13,460
  • 29
  • 152
  • 331
  • Related: [Inline image attachment on Gmail from GDrive - Web Applications Stack Exchange](https://webapps.stackexchange.com/q/108521/22453) – brasofilo Dec 09 '18 at 16:27
  • If you using nodemailer, check the solution [here](https://stackoverflow.com/questions/41946783/gmail-blocking-small-embedded-inline-images-in-email-template/68532260#68532260) – Marvin Correia Jul 26 '21 at 15:07

4 Answers4

56

Google refuses to show images with data url in Gmail's web interface. It's a known problem (in Google's view a security measure) for a long time highly criticized.

The good news is that you have another option except for using external images.

Using an inline attachment with a Content-ID works with Gmail.

After adding your images as inline attachments you'll need to point CID URLs instead of Data URLs in the html body.

There are plenty of modern libraries that will allow you to send emails with inline attachments easily. But I wrote a sample script in VBScript with CDO library, ready to use if you have a box Windows 2000+ installed.

Let's prepare the test environment.

Put the files in a directory as in the screenshot below.

enter image description here

tpl.html is the template file you gave. You'll need to make some changes in this file.

Replace both img elements with the following respectively. Note that data urls gone. image1 and image2 are the Content IDs specified for each inline attachments in the script. Nothing associated with file names here.

<img src="cid:image1" alt="SpaceImage" title="Space Image" style="display: block" width="225" height="126" />
<img src="cid:image2" alt="HostImage" title="Host Image" style="display: block" width="225" height="225" />

Embedded.vbs:

MsgBox "Wait while your email is being sent.", vbOKOnly Or vbInformation

'************ CONFIGURATION *************
Const smtpUsername = "..."
Const smtpPassword = "..."
Const smtpHost = "smtp.sendgrid.net"
Const smtpPort = 587
Const senderEmail = "...@..."
Const recipientEmail = "...@gmail.com"
'************ CONFIGURATION *************

Const cdoRefTypeId = 0

Set Fso = CreateObject("Scripting.FileSystemObject")

Set objMail = CreateObject("CDO.Message")
With objMail.Configuration
    .Fields("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate") = 1
    .Fields("http://schemas.microsoft.com/cdo/configuration/sendusername") = smtpUsername
    .Fields("http://schemas.microsoft.com/cdo/configuration/sendpassword") = smtpPassword
    .Fields("http://schemas.microsoft.com/cdo/configuration/smtpserver") = smtpHost
    .Fields("http://schemas.microsoft.com/cdo/configuration/smtpserverport")  = smtpPort
    .Fields("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
    .Fields("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 20 'secs
    .Fields.Update
End With

With objMail
    .AutoGenerateTextBody = False
    .From = senderEmail
    .To = recipientEmail
    .Subject = "Inline Image Test"
    .BodyPart.ContentTransferEncoding = "quoted-printable"
    .BodyPart.Charset = "utf-8"
    
    ' Adding images as inline attachments with Content IDs which is used with image sources. e.g. <img src="cid:image1" .. >
    .AddRelatedBodyPart Fso.GetAbsolutePathName("image1.jpg"), "image1", cdoRefTypeId
    .AddRelatedBodyPart Fso.GetAbsolutePathName("image2.jpg"), "image2", cdoRefTypeId
    
    'append html body from file
    .HTMLBody = Fso.OpenTextFile("tpl.html").ReadAll
    .Send
End With

MsgBox "Email successfully sent! Check your inbox.", vbOKOnly Or vbInformation

Double click and wait for instructions.

See also https://stackoverflow.com/search?q=is%3Aquestion+%5Bemail%5D+inline+image

Kul-Tigin
  • 16,728
  • 1
  • 35
  • 64
  • Thank you for adding a reference to other solutions. It helped a ton! I eventually got to this link and it solved my problem: http://code.activestate.com/recipes/473810-send-an-html-email-with-embedded-image-and-plain-t/ – pandasCat May 21 '18 at 23:17
  • For Javax mail api, see https://www.tutorialspoint.com/javamail_api/javamail_api_send_inlineimage_in_email.htm – Kira Sep 04 '18 at 04:59
  • 12
    @Brethlosze So you voted down this answer because a server rejects the address you sent as sender and requires TLS which you didn't provide? This answer is nothing but a proof of concept that requires the message sent successfully. First accomplish to send email message then complain about if the images in the email message does not work. The error message is clear. If you stuck with those errors, feel free to ask a new question. – Kul-Tigin Feb 14 '19 at 09:22
9

After lot trials and failures I have found reason why Gmail does not show inline pictures. Originally I used this html:

"Some HTML text and an image \<img src="cid:image1"\>Nifty!"

and attached picture with this command (in python, but details are not important):

msg.add_related(img.read(), 'image', 'png', cid='image1')

It worked in most email clients, but not in Gmail android app and Gmail web. When I finally changed it to:

 msg.add_related(img.read(), 'image', 'png', cid='\<image1\>')

it is working in Outlook, Android Email, Android Gmail and Gmail web. This mistake is repeated in lots of examples of python libraries.

masoudmanson
  • 728
  • 6
  • 17
PetrDa
  • 91
  • 1
  • 1
8

tl;dr

Gmail and certain other clients don't like base64 encoded images.

Full Story

The very first thing I did was view "Show Original" in Gmail. To my surprise, raw content still has your embedded image data:

enter image description here

That tells me right away that gmail is simply choosing to filter this content out. I was not able to find the reason. Some guesses point out the length of encoded data itself. Others talk about the general way in which Gmail filters out images. There are even records of this technique functioning a number of years back.

In addition, when viewing the same exact email in a third party client such as Newton(formerly Cloud Magic), I do see images properly rendered.

enter image description here

All of that points to a simple, however sad, fact that gmail doesn't like inline encoded images. Not in the browser and not in their mobile apps.

In fact, at the very end I did discover a post from 2013 by Campaign Monitor blog that concludes with the same results.

Don't use inline embedded images.

Community
  • 1
  • 1
Serg Chernata
  • 12,280
  • 6
  • 32
  • 50
  • 1
    For posterity, it's well-known that [Gmail doesn't support data-uri/data-url/embedded images](https://stackoverflow.com/a/8580387/675721). This has nothing to do with `base64` encoding, the length of the data, or how Gmail filters content. Embedded images have not worked in Gmail since at least 2010, as far as I can tell. The TL;DR of your answer is still correct (don't use inline images), just don't want future readers thinking that there is a way to get this to work with Gmail - as far as I can tell, there is not. – Codebling Apr 13 '21 at 18:25
6

Are you using nodemailer?

If yes, there is the solution!

NPM has a package called nodemailer-plugin-inline-base64 that allow you to send an image with data uri to all emails providers like gmail, outlook, an others.

Setup:

yarn add nodemailer nodemailer-plugin-inline-base64

And try it out

var nodemailer = require('nodemailer');
var inlineBase64 = require('nodemailer-plugin-inline-base64');
transporter.use('compile', inlineBase64({cidPrefix: 'somePrefix_'}));
transporter.sendMail({
    from: 'me@example.com',
    to: 'hello@mixmax.com',
    html: '&lt;img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAACCAYAAACE7KJkAAAAI0lEQVRYR+3DMQ0AAAgDsKlFzZxgEhOcbdIEAIBf7Y6qqn8P0MMQZPno7TMAAAAASUVORK5CYII=">'
});

Have a nice day!

Marvin Correia
  • 851
  • 7
  • 10
  • Many thanks Marvin, works great! However, I have a side case where I need to send the email via the Gmail API (google.gmail.send), instead of nodemailer. Could I reuse this plugin to retrieve the transformed body string (and then pass it over to the GmailAPI)? Or would you have any other idea to transform base64 to CID and feed the GmailAPI? – bfredo123 Aug 12 '22 at 16:57
  • 4
    Looking further at the Nodemailer doc, it looks like this package is not (or no longer?) useful: we only need to add `attachDataUrls: true`in the sendMail options. – bfredo123 Aug 13 '22 at 13:45
  • Data URI approach does not work for Gmail, which strips the src out from the – David Min Apr 08 '23 at 12:59