solutions
solutions copied to clipboard
GMail/Sheets images embedded inline in draft email get sent as attachments only
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.
Same Problem, Have you found any solution yet?
I suspect it is some sort of security measure by Google. I got around it by using a URL image.
Sent from my iPhone
On 5 Jan 2021, at 4:47 pm, vivekagr2021 [email protected] wrote:
Same Problem, Have you found any solution yet?
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
Subscribing! It's a problem for me too!
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
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 ofmsg.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
withdata-surl="cid:
) into aninlineImages
array; and - return both modified items to
emailMessage
for use inGmailApp.sendEmail()
which was also modified to incorporate retrieval of theinlineImages
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.
@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