【问题标题】:Google Apps Script: MailApp.sendEmail() can't send anything but TEXT and HTML files, nothing else?Google Apps 脚本:MailApp.sendEmail() 只能发送 TEXT 和 HTML 文件,除此之外什么都不能发送?
【发布时间】:2020-12-23 23:38:48
【问题描述】:

我正在尝试将文件附加到我使用 Google Apps 脚本使用 MailApp.sendEmail() 发送的电子邮件中。在浏览器 JavaScript 中,我使用此代码手动读取文件,因为我已经处理了 HTML 表单中提交按钮的等效项,并且它可以工作:

  var file = document.getElementById('myfile');
  var fileInfo = [];
  if(file.files.length)        // if there is at least 1 file
  {
    if (file.files[0].size < maxEmailAttachmentSize)  // and its size is < 25M
    {
      var reader = new FileReader();
      reader.onload = function(e)
      {
        fileInfo[0] = e.target.result;
      };
      reader.readAsBinaryString(file.files[0]);
      fileInfo[1] = file.files[0].name;
      fileInfo[2] = file.files[0].type;
      fileInfo[3] = file.files[0].size;
    }
    console.log(fileInfo);   // here I see the full file and info. All looks correct.
  }

然后我将它发送到服务器。

  google.script.run.withSuccessHandler(emailSent).sendAnEmail(fileInfo);

在服务器上,我提取字段并发送电子邮件,如下所示:

  var fname    = fileInfo[1];
  var mimeType = fileInfo[2];
  var fblob    = Utilities.newBlob(fileInfo[0], mimeType, fname);
  // all looks right in the Logger at this point

  try {
    GmailApp.sendEmail(emaiRecipient, emailSubject, emailBody, 
      {
        name: 'Email Sender',  // email sender
        attachments: [fblob]
      }
    );
  catch …

当文件是文本文件或 HTML 文件时,这可以正常工作,但当文件是其他文件时则不行。该文件已发送,但它是空的并且显然已损坏。谁能看出这段代码有什么问题? (它也不适用于 MailApp.sendEmail()。)我确实在另一个 stackoverflow 帖子中看到该文档必须保存一次,但这是我绝对不想做的事情。难道没有别的办法了吗?我错过了什么?

【问题讨论】:

  • 请添加更多详细信息。你想附加什么样的文件?文件大小是多少?文件是否包含可能有害、可疑、垃圾邮件的内容? FileReader 是异步的。您的客户端代码如何处理这个问题?另外,请添加minimal reproducible example
  • 我已尝试发送 .txt、.HTML、.JPG、.PNG 和 .PDF。只有前 2 个有效。它们都相对较小,在我的控制台输出中,我看到在浏览器端读取的文件在发送到服务器之前已经完成。在服务器端,我可以看到文件内容的日志与客户端上的相同。例如,JPG 和 PNG 文件很小,显然不是可疑文件或垃圾邮件。服务器端的 Mimetypes 对于每个文件都是正确的。我的代码中一定有错误,但是什么?
  • 这能回答你的问题吗? stackoverflow.com/questions/7431365
  • @TheMaster 很有帮助。谢谢你。我试图将 readAsBinaryString() 更改为 readAsArrayBuffer() 保持所有其他内容相同,但我在服务器上收到 Uncaught TypeError 异常:由于属性中的非法值而失败:10。我可以在现有的使用 readAsArrayBuffer() 的客户端代码?我不能使用 Tanaike 的出色示例,因为我们在 Rhino JavaScript 引擎上运行,而不是 V8。我们不支持或更新最新的 JavaScript 语法。谢谢!
  • @jeff 更新到 v8。无论如何,Tanaike 的解决方案是完全客户端的。不需要v8。如果您遇到问题,那是由于其他原因,需要单独调查。

标签: javascript email google-apps-script


【解决方案1】:

修改点:

  • FileReader 与异步进程一起工作。 Rubén's comment 已经提到了这一点。
  • 在当前阶段,当二进制数据发送到Google Apps Script端时,似乎需要将其转换为字符串和字节数组。 TheMaster's comment 已经提到了这一点。
  • 为了使用您的 Google Apps 脚本,在这种情况下,我认为将文件内容转换为 int8Array 的字节数组可能是合适的。
    • 为此,我使用了readAsArrayBuffer 而不是readAsBinaryString

当以上几点反映到你的脚本中时,它变成如下。

修改后的脚本:

HTML&Javascript 端:

// Added
function getFile(file) {
  return new Promise((resolve, reject) => {
    var reader = new FileReader();
    reader.onload = (e) => resolve([...new Int8Array(e.target.result)]);
    reader.onerror = (err) => reject(err);
    reader.readAsArrayBuffer(file);
  });
}

async function main() {  // <--- Modified
  var file = document.getElementById('myfile');
  var fileInfo = [];
  if(file.files.length) {
    if (file.files[0].size < maxEmailAttachmentSize) {
      fileInfo[0] = await getFile(file.files[0]);  // <--- Modified
      fileInfo[1] = file.files[0].name;
      fileInfo[2] = file.files[0].type;
      fileInfo[3] = file.files[0].size;
    }
    console.log(fileInfo);   // here I see the full file and info. All looks correct.
    google.script.run.withSuccessHandler(emailSent).sendAnEmail(fileInfo);
  }
}
  • 虽然我不确定您的问题是否完整,但在修改后的脚本中,它假设 main() 已运行。运行main()时,文件转换为字节数组,放到fileInfo[0]中。
  • 在 Google Apps 脚本方面,fileInfovar fblob = Utilities.newBlob(fileInfo[0], mimeType, fname); 具有适用于 Google Apps 脚本的正确 blob。

Google Apps 脚本方面:

在此修改中,您的 Google Apps 脚本不会被修改。

参考资料:

补充:

这段代码看起来不错,但我们不能使用它,因为我们在 Rhino JavaScript 引擎上运行,而不是 V8。我们不支持更新的 JavaScript 语法。你能给我们一个例子来说明它是如何用旧语法完成的吗? Ref

根据你上面的评论,我修改如下。

修改后的脚本:

HTML&Javascript 端:

function main() {
  var file = document.getElementById('myfile');
  var fileInfo = [];
  if(file.files.length) {
    if (file.files[0].size < maxEmailAttachmentSize) {
      var reader = new FileReader();
      reader.onload = function(e) {
        var bytes = new Int8Array(e.target.result);
        var ar = [];
        for (var i = 0; i < bytes.length; i++) {
          ar.push(bytes[i]);
        }
        fileInfo[0] = ar;
        fileInfo[1] = file.files[0].name;
        fileInfo[2] = file.files[0].type;
        fileInfo[3] = file.files[0].size;
        console.log(fileInfo);   // here I see the full file and info. All looks correct.
        google.script.run.withSuccessHandler(emailSent).sendAnEmail(fileInfo);
      }
      reader.onerror = function(err) {
        reject(err);
      }
      reader.readAsArrayBuffer(file.files[0]);
    }
  }
}

Google Apps 脚本方面:

在此修改中,您的 Google Apps 脚本不会被修改。

【讨论】:

  • 这段代码看起来不错,但我们不能使用它,因为我们在 Rhino JavaScript 引擎上运行,而不是 V8。我们不支持更新的 JavaScript 语法。你能给我们一个例子来说明它是如何使用旧语法的吗?
  • @jeff 感谢您的回复。我带来的不便表示歉意。根据您的问题,我没有注意到您的浏览器无法使用 V8 运行时。我对此深表歉意。我更新了我的答案。你能确认一下吗?但如果您没有在 Google Apps Script 的脚本编辑器中使用 V8 运行时,上述修改可能不会影响您当前的问题。因为 HTML&Javascript 不是在服务器端运行的。那时,为了正确了解您目前的情况,您能否提供您的整个脚本来复制您的问题?我想确认一下。
  • TheMaster Mateo Randwolf 它有效! Tanaike 的第二个例子完美运行!太感谢了。谢谢大家!我已将服务器运行时切换到 V8 并没有帮助,但 TheMaster 你是对的,我们应该使用它。 (实际上我们只是在几个月前,谷歌修复的一些小错误破坏了它,我们不得不切换回 Rhino。现在一切都好。) 至于 MailApp 与 Gmail 应用程序,我只是从 MailApp 切换,因为事情不工作.我会换回来的。谢谢谢谢谢谢,尤其是田池!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-03
  • 1970-01-01
相关资源
最近更新 更多