Search code examples
google-apps-scriptgmailinline-images

How to pass inline images from Class GmailMessage's getAttachments to Class MailApp's sendEmail?


I'd like to pull inline images using GmailMessage's getAttachments and then send them via Class MailApp's sendEmail.

The problem is the former returns an array of Blob attachments, while the latter expects a JavaScript object containing a mapping from image key (String) to image data Blob.

Sample code - the tricky part is {..., inlineImages: attachments, ...}:

function test() {
  var firstThread = GmailApp.getTrashThreads(0,1)[0];
  var message = firstThread.getMessages()[0];
  var from = message.getHeader('From');
  var attachments = message.getAttachments({includeAttachments: false});
  var obj = {htmlBody: message.getBody(), inlineImages: attachments, noReply: false, replyTo: message.getFrom(), name: from};
  MailApp.sendEmail("[email protected]", 'Testing', '', obj);
}

Sample EML message (note the text/html usage of <img src="cid:key"):

MIME-Version: 1.0
Date: Thu, 22 Jul 2021 23:06:23 +0300
Message-ID: <[email protected]>
Subject: Testing
From: Me <[email protected]>
To: Someone <[email protected]>
Content-Type: multipart/related; boundary="0000000000004aee5205c7bbd26b"

--0000000000004aee5205c7bbd26b
Content-Type: multipart/alternative; boundary="0000000000004aee5005c7bbd26a"

--0000000000004aee5005c7bbd26a
Content-Type: text/plain; charset="UTF-8"

This is an inline image:
[image: image.png]
And here's another:
[image: image.png]
Thanks!

--0000000000004aee5005c7bbd26a
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">This is an inline=C2=A0image:<div><div dir=3D"ltr" class=
=3D"gmail_signature" data-smartmail=3D"gmail_signature"><div dir=3D"ltr"></=
div></div></div><div><img src=3D"cid:ii_krfchaks0" alt=3D"image.png" width=
=3D"117" height=3D"118"><br></div><div>And here&#39;s another:</div><div><i=
mg src=3D"cid:ii_krfchlll1" alt=3D"image.png" width=3D"41" height=3D"47"><b=
r></div><div>Thanks!</div></div>

--0000000000004aee5005c7bbd26a--
--0000000000004aee5205c7bbd26b
Content-Type: image/png; name="image.png"
Content-Disposition: attachment; filename="image.png"
Content-Transfer-Encoding: base64
X-Attachment-Id: ii_krfchaks0
Content-ID: <ii_krfchaks0>


--0000000000004aee5205c7bbd26b
Content-Type: image/png; name="image.png"
Content-Disposition: attachment; filename="image.png"
Content-Transfer-Encoding: base64
X-Attachment-Id: ii_krfchlll1
Content-ID: <ii_krfchlll1>


--0000000000004aee5205c7bbd26b--

Solution

  • Turns out Google Apps Script supports matchAll, which means it can be pulled off like this:

    function test() {
      var firstThread = GmailApp.getTrashThreads(0,1)[0];
      var message = firstThread.getMessages()[0];
      var from = message.getHeader('From');
      var attachments = message.getAttachments({includeAttachments: false}), inline_images = {};
      var regex = new RegExp('<img src="cid:(.*?)"', 'ig');
      var i=-1, matches = message.getBody().matchAll(regex)
      for (const match of matches) {
            i++;
            inline_images[match[1]] = attachments[i].copyBlob();
      }
      var obj = {htmlBody: message.getBody(), inlineImages: attachments, noReply: false, replyTo: message.getFrom(), name: from};
      MailApp.sendEmail("[email protected]", 'Testing', '', obj);
    }