6

Gmail 消息 getAttachments 函数未返回 inlineImages - 请参阅问题 2810 https://code.google.com/p/google-apps-script-issues/issues/detail?id=2810

我需要这样做,所以我编写了下面的代码来从消息原始内容中解析 blob 格式的内联图像,提前知道消息中的图像 cid。

但是,恐怕这种解析在我找到base64图像内容中的第一个和最后一个字符的方式上是相当脆弱的,不是吗?

有没有更好的方法来做到这一点?

问候, 福斯托

var rawc = message.getRawContent();
var b64c1 = rawc.lastIndexOf(cid) + cid.length + 3; // first character in image base64
var b64cn = rawc.substr(b64c1).indexOf("--") - 3; // last character in image base64
var imgb64 = rawc.substring(b64c1, b64c1 + b64cn + 1); // is this fragile or safe enough?
var imgblob = Utilities.newBlob(Utilities.base64Decode(imgb64), "image/jpeg", cid); // decode and blob
4

2 回答 2

6

我已经多次遇到这个问题,我认为我有一个非常通用的案例解决方案。获取非嵌入图像也是一个问题。

我不确定我的解析比你的更脆弱。最后,我multipart通过抓住以 开头的周围线条来吸出部分'--'。其他一切只是确保我可以在下次需要时使用它而无需过多修改代码。我收到了一些似乎没有遵循\r\n并导致问题的电子邮件:需要注意的事情。

getInlineImages函数将获取消息的原始内容并返回一个对象数组。每个对象都将具有 img 标签的 src 和图像附带的 blob。如果您只想要内联图像,您可以选择忽略不以“cid”开头的任何内容。

getBlobFromMessage函数将获取消息的原始内容和 img 标签的 src(包括“cid”)并返回相关的 blob。

您可以在此处查看注释的代码。

function getInlineImages(rawContent) {
  var url = /^https?:\/\//, cid = /^cid:/;
  var imgtags = rawContent.match(/<img.*?>(.*?<\/img>)?/gi);
  return imgtags ? imgtags.map(function(imgTag) {
    var img = {src: Xml.parse(imgTag,true).html.body.img.src};
    img.blob = url.test(img.src) ? UrlFetchApp.fetch(img.src).getBlob()
             : cid.test(img.src) ? getBlobFromMessage(rawContent,img.src)
             : null;
    return img;
  }) : [];
}

function getBlobFromMessage(rawContent,src) {
  var cidIndex = src.search(/cid:/i);
  if(cidIndex === -1) throw Utilities.formatString("Did not find cid: prefix for inline refenece: %s", src)

  var itemId = src.substr(cidIndex + 4);
  var contentIdIndex = rawContent.search("Content-ID:.*?" + itemId);
  if(contentIdIndex === -1) throw Utilities.formatString("Item with ID %s not found.",src);

  var previousBoundaryIndex = rawContent.lastIndexOf("\r\n--",contentIdIndex);
  var nextBoundaryIndex = rawContent.indexOf("\r\n--",previousBoundaryIndex+1);
  var part = rawContent.substring(previousBoundaryIndex,nextBoundaryIndex);

  var contentTransferEncodingLine = part.match(/Content-Transfer-Encoding:.*?\r\n/i)[0];
  var encoding = contentTransferEncodingLine.split(":")[1].trim();
  if(encoding != "base64") throw Utilities.formatString("Unhandled encoding type: %s",encoding);

  var contentTypeLine = part.match(/Content-Type:.*?\r\n/i)[0];
  var contentType = contentTypeLine.split(":")[1].split(";")[0].trim();

  var startOfBlob = part.indexOf("\r\n\r\n");
  var blobText = part.substring(startOfBlob).replace("\r\n",""); 
  return Utilities.newBlob(Utilities.base64Decode(blobText),contentType,itemId);
}
于 2013-06-24T04:19:33.783 回答
0

解决此问题的最新方法。

问题

例如,这是使用 .getBody() 检索到的电子邮件正文

<div dir="ltr"><div><img src="?view=att&amp;th=1401f70d4881e07f&amp;attid=0.3&amp;disp=emb&amp;realattid=ii_1401f6fc7824ebe1&amp;zw&amp;atsh=1" alt="Inline image 4" width="200" height="180"><br></div><div><br></div><img src="?view=att&amp;th=1401f70d4881e07f&amp;attid=0.2&amp;disp=emb&amp;realattid=ii_1401f6e6c1d46c4b&amp;zw&amp;atsh=1" alt="Inline image 2" width="200" height="65"><div><br></div><div>
jtykuykyu</div><div><br></div><div><img src="?view=att&amp;th=1401f70d4881e07f&amp;attid=0.1&amp;disp=emb&amp;realattid=ii_1401f6e9df3a4b1c&amp;zw&amp;atsh=1" alt="Inline image 3" width="200" height="82"><br><div><br></div><div><br></div></div></div>

这是电子邮件的附件列表(其中是我们的内联图像):

[13-07-30 08:28:08:378 CEST] 屏幕截图 2013-07-12 下午 1.54.31.png

[13-07-30 08:28:08:379 CEST] 屏幕截图 2013-07-23 下午 5.38.51.png

[13-07-30 08:28:08:380 CEST] 屏幕截图 2013-07-25 上午 9.05.15.png

[13-07-30 08:28:08:381 CEST] test2.png

如您所见,这些图像的名称与 img 标签中可用的信息之间没有任何联系,因此没有安全的方法可以仅使用这些信息来重建正确的电子邮件。

解决方案

如何解决?我们可以使用 .getRawContent() 方法来获取实际的电子邮件并对其进行解析以获取我们需要的信息。具体来说,此方法为我们提供了附件名称和电子邮件正文中可用的“realattid”之间的关系:

内容类型:图片/png;name="2013-07-25 上午 9.05.15 截屏.png"

内容传输编码:base64

内容 ID:

X 附件 ID:ii_1401f6e9df3a4b1c

代码片段

这是一个代码片段:

- 检索电子邮件的正文和附件

- 获取正文中的所有 img 标签,并查看哪些标签链接到电子邮件中的附件

- 获取每个图像的“realattid”并使用 .getRawContent() 将此“realattid”链接到正确的附件

- 替换 img 标签以正确链接到正确的附件

- 表示这个附件不再是简单的附件而是内嵌图片

- 完成所有操作后,您就拥有了发送此电子邮件副本所需的所有数据,并显示正确的内嵌图像。

 //////////////////////////////////////////////////////////////////////////////
  // Get inline images and make sure they stay as inline images
  //////////////////////////////////////////////////////////////////////////////
  var emailTemplate = selectedTemplate.getBody();
  var rawContent = selectedTemplate.getRawContent();
  var attachments = selectedTemplate.getAttachments();

  var regMessageId = new RegExp(selectedTemplate.getId(), "g");
  if (emailTemplate.match(regMessageId) != null) {
    var inlineImages = {};
    var nbrOfImg = emailTemplate.match(regMessageId).length;
    var imgVars = emailTemplate.match(/<img[^>]+>/g);
    var imgToReplace = [];
    if(imgVars != null){
      for (var i = 0; i < imgVars.length; i++) {
        if (imgVars[i].search(regMessageId) != -1) {
          var id = imgVars[i].match(/realattid=([^&]+)&/);
          if (id != null) {
            var temp = rawContent.split(id[1])[1];
            temp = temp.substr(temp.lastIndexOf('Content-Type'));
            var imgTitle = temp.match(/name="([^"]+)"/);
            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(/src="[^\"]+\"/, "src=\"cid:" + imgToReplace[i][2] + "\"");
          emailTemplate = emailTemplate.replace(imgToReplace[i][1], newImg);
        }
      }
    }
  }
  //////////////////////////////////////////////////////////////////////////////
  var message = {
    htmlBody: emailTemplate,
    subject: selectedTemplate.getSubject(),
    attachments: attachments,
    inlineImages: inlineImages
  }
于 2018-04-03T03:01:35.310 回答