Gmail API发送的邮件中附件丢失,但仅限于收件人。

16
当使用JavaScript调用Gmail API发送带有HTML正文和约100KB的PDF附件的邮件时,该附件会正确地附加到发件人的Gmail已发送文件夹中的邮件中,但在收件人的邮件中不会显示。API调用是向以下地址进行POST请求:
https://www.googleapis.com/upload/gmail/v1/users/me/messages/send?uploadType=media

发送到API的请求类似于这样:

{
  "headers": {
    "Authorization": "Bearer {auth_token}"
  },
  "method": "POST",
  "contentType": "message/rfc822",
  "contentLength": 134044,
  "payload": "{see_below}",
}

请求正文为:

MIME-Version: 1.0
To: =?utf-8?B?TWlrZSBD?=<recipient@test.com>
CC: =?utf-8?B?TWlrZSBD?=<secondrecipient@gmail.com>
BCC: =?utf-8?B??=<bccrecipient@test.com>
From: =?utf-8?B?TWlrZSBxWXsd2lr?=<sender@test.com>
Subject: =?utf-8?B?subjectLine-removedForThisPost?=
Content-Type: multipart/alternative; boundary=__boundary__

--__boundary__
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64

{base64_encoded_string}

--__boundary__
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: base64

{base64_encoded_string}

--__boundary__
Content-Type: application/pdf; name="File Name.pdf"
Content-Disposition: attachment; filename="File Name.pdf"
Content-Transfer-Encoding: base64

{base64_encoded_string}

--__boundary__--

注意:Gmail API上传附件文档指出,在上传“简单”附件(小于5MB)时需要Content-Length。我使请求包括Content-Length,其值为PDF附件的总字节数。然而,我发现负载中没有包含Content-Length
我尝试将消息的Content-Typemultipart/alternative更改为multipart/mixed - 这样做会使PDF附件正确附加到收件人的消息中,但消息的HTML正文被呈现为纯文本(显示HTML标签),并且还有一个名为noname.html的附件,其中包含以HTML格式呈现的HTML内容。
我需要确保收件人的邮件既有HTML渲染的正文,又有PDF附件。
更新:我已经上传了邮件的原始示例这里。左边是发送的消息,右边是接收的消息。

你尝试过引用你的边界(boundary="__boundary__")并使用最终边界(--__boundary__--)吗?尝试类似于这样的东西,看看是否有效。 - Tholle
刚刚意识到我的有效载荷确实包括 --__boundary__-- 的最终边界,但当我将其粘贴在这里时,它被截断了,因为控制台日志消息由于超长的附件 base64 字符串而被截断。至于双引号 - 我将它们添加到第一个 Content-Type: 行中,但它并没有改变行为 - 它与或没有它一样工作。 - Employee
只是为了确认一下,当从用户界面发送时,是否收到了相同的附件?此外,这是否发生在所有收件人身上?还是只针对特定的域/用户? - jds1993
是的,在Gmail UI中发送附件的消息时,接收方可以正确收到。我还进行了多个不同附件的测试,以排除文件问题的可能性。我也尝试将邮件发送给几个不同领域的收件人,但所有收件人都无法看到该附件。 - Employee
2个回答

6

只需将:

Content-Type: multipart/alternative; boundary=__boundary__

替换为:

Content-Type: multipart/mixed; boundary=__boundary__

这是我的完整JS函数。

function createMimeMessage_(msg) {

var nl = "\n"; var boundary = "ctrlq_dot_org";

var mimeBody = [

"MIME-Version: 1.0",
"To: "      + msg.to.email,//+ encode_(msg.to.name) + "<" + msg.to.email + ">",
"Cc: "      + msg.cc.email,
"Bcc: "      + msg.bcc.email,
"From: "    + msg.from.email,//+ encode_(msg.from.name) + "<" + msg.from.email + ">",
"Subject: " + encode_(msg.subject), // takes care of accented characters
"In-Reply-To: " + (msg.reply_to || ""),
"References: " + (msg.reply_to || ""),

"Content-Type: multipart/mixed; boundary=" + boundary + nl,
"--" + boundary,

// "Content-Type: text/plain; charset=UTF-8",
// "Content-Transfer-Encoding: 7bit",
// "Content-Disposition: inline" + nl,
// msg.body.text + nl,
// "--" + boundary,

"Content-Type: text/html; charset=UTF-8",
"Content-Transfer-Encoding: base64" + nl,
new Buffer(msg.body.text).toString('base64') + nl,

];

for (var i = 0; i < msg.files.length; i++) {

var attachment = [
  "--" + boundary,
  "Content-Type: " + msg.files[i].mimeType + '; name="' + msg.files[i].fileName + '"',
  'Content-Disposition: attachment; filename="' + msg.files[i].fileName + '"',
  "Content-Transfer-Encoding: base64" + nl,
  msg.files[i].bytes
];

mimeBody.push(attachment.join(nl));

}

mimeBody.push("--" + boundary + "--"); //console.log(mimeBody);

return mimeBody.join(nl);

}


我在原始问题中提到我已经尝试过这个方法:这样做确实使得PDF附件正确地附加在收件人的消息中,但是消息的HTML正文会被渲染为纯文本(显示HTML标签),并且还会有一个名为noname.html的附加文件,其中包含渲染为HTML的HTML内容。 - Employee
嘿,感谢您包含整个函数。 但是,看起来您只是从Amit Agarwal的页面[此处](https://ctrlq.org/code/20133-create-gmail-drafts-attachments)复制了大部分,如果不是全部,这就是我最初获取大部分代码的地方,因此它几乎完全匹配。 - Employee
没错,我是从那个网站上复制的。但是我做了一些修改以使它能够满足我的需求。 - Tiger developer

1
你的问题有两个部分:
1. 我该如何确保附件能够成功发送给收件人? 2. 我该如何同时包含附件和HTML格式的纯文本备选项?
这个问题已经被Tiger开发者部分回答了(使用“multipart/alternative”代替“multipart/mixed”)。但正如你所指出的,这样做会导致你无法得到备选的纯文本内容。这是因为你删除了“multipart/alternative”,而它的特定作用就是提供备选内容。
你需要做的是创建第二个边界,并将纯文本和HTML部分组合在一起。请参考以下示例,也是从CTRLQ获取的,注意我包含的“altBoundary”。
function createMimeMessage_(msg) {

  var nl = "\n";
  var boundary = "__ctrlq_dot_org__";
  var altBoundary = "__alt_ctrlq_dot_org__";

  var mimeBody = [

    "MIME-Version: 1.0",
    "To: "      + encode_(msg.to.name) + "<" + msg.to.email + ">",
    "From: "    + encode_(msg.from.name) + "<" + msg.from.email + ">",
    "Subject: " + encode_(msg.subject), // takes care of accented characters

    "Content-Type: multipart/mixed; boundary=" + boundary + nl,
    "--" + boundary,

    "Content-Type: multipart/alternative; boundary=" + altBoundary + nl,
    "--" + altBoundary,

    "Content-Type: text/plain; charset=UTF-8",
    "Content-Transfer-Encoding: base64" + nl,
    Utilities.base64Encode(msg.body.text, Utilities.Charset.UTF_8) + nl,
    "--" + altBoundary,

    "Content-Type: text/html; charset=UTF-8",
    "Content-Transfer-Encoding: base64" + nl,
    Utilities.base64Encode(msg.body.html, Utilities.Charset.UTF_8) + nl,

    "--" + altBoundary + "--"

  ];

  for (var i = 0; i < msg.files.length; i++) {

    var attachment = [
      "--" + boundary,
      "Content-Type: " + msg.files[i].mimeType + '; name="' + msg.files[i].fileName + '"',
      'Content-Disposition: attachment; filename="' + msg.files[i].fileName + '"',
      "Content-Transfer-Encoding: base64" + nl,
      msg.files[i].bytes
    ];

    mimeBody.push(attachment.join(nl));

  }

  mimeBody.push("--" + boundary + "--");

  return mimeBody.join(nl);

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接