Skip to content
This repository has been archived by the owner on Dec 7, 2023. It is now read-only.

GMail/Sheets images embedded inline in draft email get sent as attachments only #163

Open
ChrisE40 opened this issue Nov 27, 2020 · 6 comments

Comments

@ChrisE40
Copy link

I thought this might be a GMail problem but am now thinking it must be caused by the script that sends the emails. The embedded image looks fine in the GMail draft. The recipient gets an image placemark with an x in the middle (not found) and the image is there as an attachment. Means I can't have a letterhead on my emails.

@vivekagr2021
Copy link

Same Problem, Have you found any solution yet?

@ChrisE40
Copy link
Author

ChrisE40 commented Jan 5, 2021 via email

@BenjaminCharlton
Copy link

Subscribing! It's a problem for me too!

@rawaps
Copy link

rawaps commented Jan 31, 2021

in your draft do not upload or drag and drop the picture

Solution: Click on insert photo and select web address URL (the URL should be public) and paste the URL of your pic.
Note: if your photo is local, you can use imgBB to upload your pic online and get the URL

@tyochelson-lwhs
Copy link

Ran into this issue as well while setting up mail merge for one of our staff members.

Began by looking around the Web; found code at https://stackoverflow.com/a/49621562 which provided a possible fix, but after modding the @mhawksey code to incorporate the code from the SO answer as part of getGmailTemplateFromDrafts_() I still couldn't get things working properly.

After a few (dozen) iterations of banging my head on it, I sent a message with inlines to myself, and compared the HTML code from "Show Original" to both a Logger.log of msg.getBody() from the Draft message and a "Show Original" from one of my failed Merge messages, and noted the following:

Draft message HTML Body <img> tag (from msg.getBody())
<img data-surl="cid:ii__abcdefghi_" src="cid:ii__abcdefghi_" alt="_Inserted Inline Image_.jpg" width="250" height="150">

Mail Merge Sent message HTML Body <img> tag
<img data-surl="cid:ii__abcdefghi_" src="cid:ii__abcdefghi_" alt="_Inserted Inline Image_.jpg" width="250" height="150">

Human Sent message HTML Body <img> tag
<img src="cid:ii__abcdefghi_" alt="_Inserted Inline Image_.jpg" width="250" height="150">

Essentially, the "draft" message <img> tags incorporate the "data-surl" parameter, and the failed Merge message copies those verbatim...but the Human message <img> tags do not.

My deduction is that Google changed how they handled Inline images at some point between when @mhawksey wrote getGmailTemplateFromDrafts_() and February 8th, 2021 (which is when I started noodling with this). I found backup for that deduction at https://issuetracker.google.com/issues/36757948 and https://issuetracker.google.com/issues/36755796.

Now, knowing what a "proper" <img> tag should look like for an inline image, and having learned from https://developers.google.com/apps-script/reference/gmail/gmail-app#sendEmail(String,String,String,Object) that one of the optional Object parameters is inlineImages, I was able to mod the SO code and getGmailTemplateFromDrafts_() to:

  • create an html_Body variable to contain the contents of msg.getBody() for modification;
  • modify the <img> tags in html_Body to conform to the new format for actual messages (vs drafts);
  • iteratively extract just the Inline images from attachments (keying by RegEx .match with data-surl="cid:) into an inlineImages array; and
  • return both modified items to emailMessage for use in GmailApp.sendEmail() which was also modified to incorporate retrieval of the inlineImages array value.

Here's the code I put together; it could probably be more optimized, but programming isn't my forte.

Line 98 (becomes 2 lines):

          attachments: emailTemplate.attachments, 
          inlineImages: emailTemplate.inlineImages

Lines 114-133 (too many changes to break out):

  /**
   * Get a Gmail draft message by matching the subject line.
   * @param {string} subject_line to search for draft message
   * @return {object} containing the subject, plain and html message body and attachments
   * 
   * Incorporates code to correctly parse and insert inline images
   * @see https://stackoverflow.com/a/49621562
  */
  function getGmailTemplateFromDrafts_(subject_line){
    try {
      // get drafts
      const drafts = GmailApp.getDrafts();
      // filter the drafts that match subject line
      const draft = drafts.filter(subjectFilter_(subject_line))[0];
      // get the message object
      const msg = draft.getMessage();
      // getting attachments so they can be included in the merge
      const attachments = msg.getAttachments();
      // get HTML body text
      var html_Body = msg.getBody();
      // Configure a RegExp for identifying draft Image Tags that indicate "inline" images
      const regDraftImgTag = new RegExp('img data-surl="cid:', "g");

      if (html_Body.match(regDraftImgTag) != null) {
        var inlineImages = {};
        var imgVars = html_Body.match(/<img[^>]+>/g);
        var imgToReplace = [];
        if(imgVars != null){
          for (var i = 0; i < imgVars.length; i++) {
            if (imgVars[i].search(regDraftImgTag) != -1) {
              var id = imgVars[i].match(/src="cid:([^"]+)"/);
              if (id != null) {
                var imgTitle = imgVars[i].match(/alt="([^"]+)"/);
                if (imgTitle != null) imgToReplace.push([imgTitle[1], imgVars[i], id[1]]);
              }
            }
          }
        }
        for (var i = 0; i < imgToReplace.length; i++) {
          for (var j = 0; j < attachments.length; j++) {
            if(attachments[j].getName() == imgToReplace[i][0]) {
              inlineImages[imgToReplace[i][2]] = attachments[j].copyBlob();
              attachments.splice(j, 1);
              var newImg = imgToReplace[i][1].replace(/ data-surl="[^"]+"/, "");
              html_Body = html_Body.replace(imgToReplace[i][1], newImg);
            }
          }
        }
      }
      return {message: {subject: subject_line, text: msg.getPlainBody(), html: html_Body }, 
              attachments: attachments, inlineImages: inlineImages};
    } catch(e) {
      throw new Error("Oops - can't find Gmail draft");
    }

@mhawksey, I'd be happy to submit this as a patch to your code if you want.

mhawksey added a commit to mhawksey/solutions that referenced this issue Feb 12, 2021
mhawksey added a commit to mhawksey/solutions that referenced this issue Feb 12, 2021
mhawksey added a commit to mhawksey/solutions that referenced this issue Feb 14, 2021
Added handling of inline images inserted in the Gmail draft via image upload
@mhawksey
Copy link
Contributor

@tyochelson-lwhs thanks for your investigation and reporting. Looking into this I think you are right the the inlineImages object needs to be rebuild. As it happens I had also recently come across a SO contribution, which provided a way to rebuild the inlineImages object whilst using the existing cid references. I've submitted a patch which is included in this modified version of the solution Google Sheet . If you could test and provide feedback that would be great

sqrrrl pushed a commit that referenced this issue Feb 17, 2021
… from the Gmail draft (#173)

* Initial commit of Mail Merge solution

Create and distribute visual rich mail merges with Gmail and Google Sheets

* Minor edits to readme text

Edits based on comments in #65 (comment)

* update to head

* Updated to head

* Fix for null error when sending emails without variable tags

Fix for issue #98 on gsuitedevs branch #98

* Refactoring and V8 update

Includes ability for using formatted Google Sheets cell values for currencies, dates and more as well as detecting/ignoring filtered hidden rows. Code also updated to highlight Gmail `.sendMail()` options

* Updated mail merge solution moving Advanced Sheets Service and moving to V8

Removed dependency on Advanced Sheets Service

* Mail merge fix to escape cell data

Fix for #127 to escape cell data to make JSON safe

* Fixed EOF

https://github.com/gsuitedevs/solutions/pull/130/files/a8d745d949b33484dd6a33da4c0dfcfb1202cfdf#r431210317

* Inline image handling for mail merge

Fix for the inline image issue #163

* Nit fix for mail merge #163

* Revert "Inline image handling for mail merge"

This reverts commit 363060c.

* Fix for mail merge inline image handling #163

Added handling of inline images inserted in the Gmail draft via image upload
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants