在 Google Apps 脚本中使用高级 Gmail 服务创建与表情符号兼容的 Gmail 草稿
Posted
技术标签:
【中文标题】在 Google Apps 脚本中使用高级 Gmail 服务创建与表情符号兼容的 Gmail 草稿【英文标题】:Creating an Emoji-Compatible Gmail draft with Advanced Gmail Service in Google Apps Script 【发布时间】:2021-11-28 09:24:33 【问题描述】:我正在尝试使用 Gmail 高级服务create a Gmail draft。我需要的是让body
在bytes format 中包含data
。我构建了以下功能:
const createDraftWithAdvancedService = () =>
Gmail.Users.Drafts.create(
message:
payload:
parts: [
body:
data: [
42,
123,
123,
80,
114,
],
],
headers: [
"value": "This is a test subject",
"name": "Subject"
,
]
, 'user@domain.com');
但是,当我运行它时,我收到以下错误:
GoogleJsonResponseException:对 gmail.users.drafts.create 的 API 调用失败并出现错误:收到的 JSON 负载无效。 'draft.message.payload.parts[0].body' 中的未知名称“数据”:原始字段不重复,无法启动列表。
这个错误看起来很奇怪,因为我正确地遵循了索引(或者我在检查一百次之后相信)。
我在这里错过了什么?
更新
我将字节字符串格式化为数组的原因是,当您阅读草稿时,这就是 Gmail API 返回的内容。如果您有不同的工作代码,我会全力以赴。而且我不能使用raw
,我需要设置字节字符串。
这是一个如何检索消息对象及其格式的示例:
我的草稿消息:
检索此草稿消息的脚本:
const getMessage = () =>
const id = 'r-8326849559354985208';
const msg = Gmail.Users.Drafts.get('user@domain.com', id);
console.log(JSON.stringify(msg, null, 2));
脚本的输出:
"message":
"internalDate": "1633701716000",
"snippet": "Draft body",
"labelIds": [
"DRAFT"
],
"historyId": "954861",
"sizeEstimate": 534,
"payload":
"filename": "",
"parts": [
"partId": "0",
"headers": [
"value": "text/plain; charset=\"UTF-8\"",
"name": "Content-Type"
],
"filename": "",
"body":
"data": [
68,
114,
97,
102,
116,
32,
98,
111,
100,
121,
13,
10
],
"size": 12
,
"mimeType": "text/plain"
,
"headers": [
"value": "text/html; charset=\"UTF-8\"",
"name": "Content-Type"
],
"partId": "1",
"body":
"size": 33,
"data": [
60,
100,
105,
118,
32,
100,
105,
114,
61,
34,
108,
116,
114,
34,
62,
68,
114,
97,
102,
116,
32,
98,
111,
100,
121,
60,
47,
100,
105,
118,
62,
13,
10
]
,
"mimeType": "text/html",
"filename": ""
],
"body":
"size": 0
,
"headers": [
"value": "1.0",
"name": "MIME-Version"
,
"value": "Fri, 8 Oct 2021 16:01:56 +0200",
"name": "Date"
,
"value": "<CADVhnimBt3Jdod1wBgGUgB_75yrsoJMwM68mtYKmX6cN39=CNQ@mail.gmail.com>",
"name": "Message-ID"
,
"name": "Subject",
"value": "Draft subject"
,
"name": "From",
"value": "\"KOSTYUK, Dmitry\" <user@domain.com>"
,
"value": "multipart/alternative; boundary=\"00000000000088918105cdd7d2e1\"",
"name": "Content-Type"
],
"mimeType": "multipart/alternative",
"partId": ""
,
"id": "17c6035e45454be8",
"threadId": "17c6035c50e83b2f"
,
"id": "r-8326849559354985208"
【问题讨论】:
> base64 编码的字符串。 应该是string
。我认为您不应该使用payload
,而应该使用message:raw:"b64string"
见python guide。你需要raw
。创建没有库的 MIMEText 有点困难,但可行。我认为@Tanaike 对创建符合 RFC2822 的 MIMEText 有一些答案
给你go
@TheMaster 谢谢,我能够在引用的答案中调整高级 Gmail 服务部分,以使事情对我有用。我会按照你的建议尽快写一个答案。 *** 似乎是唯一记录此行为的地方。我现在也必须弄清楚附件,但这是一个不同的问题
【参考方案1】:
经过一些研究和学习 RFC2822 MIMEText 语法,我对这个问题有了明确的答案。我分三部分回答:
-
什么不起作用
解决方案一:艰难的道路
解决方案二:新的简单方法
什么没用
像我在问题中所做的那样,使用实际的 Message
对象不起作用。不要问我为什么,它没有在任何地方记录,它只是不起作用。即使您通过Gmail.Users.Drafts.get()
从另一条消息中复制了 JSON 对象的全部或现有部分,GAS 仍然会抛出错误。
所以输入的内容不是返回的内容,即使文档另有说明。
因此,唯一的解决方案是使用消息对象的 raw
属性,该属性必须是 RFC2822 格式的 base-64 编码字符串。
解决方案一:艰难的道路
结合here 和here 的解决方案,可以创建一个基本功能,该功能可以生成带有表情符号的草稿消息:
function convert(toEmail, fromEmail, subject, body)
body = Utilities.base64Encode(body, Utilities.Charset.UTF_8);
subject = Utilities.base64Encode(subject, Utilities.Charset.UTF_8);
const boundary = "boundaryboundary";
const mailData = [
"MIME-Version: 1.0",
"To: " + toEmail,
"From: " + fromEmail,
"Subject: =?utf-8?B?" + subject + "?=",
"Content-Type: multipart/alternative; boundary=" + boundary,
"",
"--" + boundary,
"Content-Type: text/plain; charset=UTF-8",
"",
body,
"",
"--" + boundary,
"Content-Type: text/html; charset=UTF-8",
"Content-Transfer-Encoding: base64",
"",
body,
"",
"--" + boundary,
].join("\r\n");
return mailData;
function makeApiDraft()
const subject = "Hello MimeText World";
const body = 'This is a plain text message';
const me = Session.getActiveUser().getEmail();
const raw = convert('test@test.com', me, subject, body);
const b64 = Utilities.base64EncodeWebSafe(raw);
console.log(raw)
Gmail.Users.Drafts.create( message: raw: raw , me);
这个解决方案没有错,它有效。但是,如果您想超越此示例,例如添加多个收件人、具有不同的纯文本和 html 正文、管理附件等,您将不得不手动编写所有代码,这需要了解 RFC2822 MIMEText 格式。
因此进入新的更简单的解决方案。
解决方案二:新的简单方法
我偶然发现了this library,它生成了用 Node.js 编写的 MIMEText 电子邮件。所以我认为完美。我分叉了 repo 并调整了一些东西以使其与 GAS 兼容,特别是:
-
Base 64 编码使用
Utilities.base64Encode()
和Utilities.base64EncodeWebSafe()
完成
只需传递 GAS DriveApp.File
对象即可完成附加文件
我确保正确的 MIMEText 标头和 base 64 编码存在于需要它们的位置。
当我的拉取请求处于待处理状态时,我使用 Webpack 转译了整个内容(因为该库确实具有依赖项)并将其发布为该 ID 下的 GAS 库:
1HzFRRghlhuCDl0FUnuE9uKAK39GfeuUJAE3oOsjv74Qjq1UW8YEboEit
这里是an example project,可以用来测试一下,不过代码基本如下:
const testMimeText = () =>
const message = MimeText;
message.setSender(
name: 'Dmitry Kostyuk',
addr: 'dmitry.kostyuk@gmail.com',
);
const file = DriveApp.getFileById('1pdMwlGL1WZTbi-Q2-Fc7nBm-9NKphkKg');
const me = Session.getActiveUser().getEmail();
message.setRecipient('dmitry.kostyuk@gmail.com');
message.setSubject('Hello MimeText World!');
message.setMessage('This is a plain text message ' + getAllEmojis(), 'text/plain');
message.setMessage('<p>This is an html message</p><p>' + getAllEmojis() + '</p>\r\n\r\n', 'text/html');
message.setAttachments([file]);
const raw = message.asEncoded();
Gmail.Users.Drafts.create( message: raw: raw , me);
const getDriveAuth = () => DriveApp.getRootFolder();
我想我掉进了一个我没想到的兔子洞,但我对结果很满意:)
【讨论】:
以上是关于在 Google Apps 脚本中使用高级 Gmail 服务创建与表情符号兼容的 Gmail 草稿的主要内容,如果未能解决你的问题,请参考以下文章
在 Google Apps 脚本中使用 Mandrill API
在 Google Apps 脚本中使用 BigQuery 连接到 Google 电子表格
Google 表单 - 使用 Google Apps 脚本在项目中添加自定义按钮“更多信息”