Gmail API 在 Javascript 中解码消息
Posted
技术标签:
【中文标题】Gmail API 在 Javascript 中解码消息【英文标题】:Gmail API decoding messages in Javascript 【发布时间】:2014-09-08 18:22:29 【问题描述】:我在解码使用 Gmail API 收到的电子邮件的消息正文时遇到严重问题。我想获取消息内容并将内容放在一个 div 中。我正在使用 base64 解码器,我知道它不会解码以不同方式编码的电子邮件,但我不确定如何检查电子邮件以决定使用哪个解码器 - 说它们是 utf-8 编码的电子邮件被成功解码base64 解码器,但不是 utf-8 解码器。
我已经研究了几天的电子邮件解码,我了解到我在这里有点不合群。我以前没有做太多关于电子邮件编码的工作。这是我用来获取电子邮件的代码:
gapi.client.load('gmail', 'v1', function()
var request = gapi.client.gmail.users.messages.list(
labelIds: ['INBOX']
);
request.execute(function(resp)
document.getElementById('email-announcement').innerhtml = '<i>Hello! I am reading your <b>inbox</b> emails.</i><br><br>------<br>';
var content = document.getElementById("message-list");
if (resp.messages == null)
content.innerHTML = "<b>Your inbox is empty.</b>";
else
var encodings = 0;
content.innerHTML = "";
angular.forEach(resp.messages, function(message)
var email = gapi.client.gmail.users.messages.get(
'id': message.id
);
email.execute(function(stuff)
if (stuff.payload == null)
console.log("Payload null: " + message.id);
var header = "";
var sender = "";
angular.forEach(stuff.payload.headers, function(item)
if (item.name == "Subject")
header = item.value;
if (item.name == "From")
sender = item.value;
)
try
var contents = "";
if (stuff.payload.parts == null)
contents = base64.decode(stuff.payload.body.data);
else
contents = base64.decode(stuff.payload.parts[0].body.data);
content.innerHTML += '<b>Subject: ' + header + '</b><br>';
content.innerHTML += '<b>From: ' + sender + '</b><br>';
content.innerHTML += contents + "<br><br>";
catch (err)
console.log("Encoding error: " + encodings++);
)
)
);
);
我正在执行一些检查和调试,所以有剩余的console.log
和其他一些仅用于测试的东西。不过,您可以在这里看到我正在尝试做的事情。
解码从 Gmail API 提取的电子邮件的最佳方法是什么?我是否应该尝试将电子邮件放入<script>
的charset
和type
属性与电子邮件的编码内容匹配?我相信我记得 charset 仅适用于 src
属性,而我在这里没有。有什么建议吗?
【问题讨论】:
【参考方案1】:对于我正在编写的原型应用程序,以下代码适用于我:
var base64 = require('js-base64').Base64;
// js-base64 is working fine for me.
var bodyData = message.payload.body.data;
// Simplified code: you'd need to check for multipart.
base64.decode(bodyData.replace(/-/g, '+').replace(/_/g, '/'));
// If you're going to use a different library other than js-base64,
// you may need to replace some characters before passing it to the decoder.
注意:这些点没有明确记录,可能是错误的:
users.messages: get
API 默认返回“已解析的正文内容”。无论Content-Type
和Content-Transfer-Encoding
标头如何,这些数据似乎总是以UTF-8 和Base64 编码。
例如,我的代码在解析带有以下标头的电子邮件时没有问题:Content-Type: text/plain; charset=ISO-2022-JP
、Content-Transfer-Encoding: 7bit
。
Base64编码varies among various implementations的映射表。 Gmail API 使用-
和_
作为表格的最后两个字符,由RFC 4648 的“URL 和文件名安全字母”1 定义。
检查您的 Base64 库是否使用不同的映射表。如果是这样,请将这些字符替换为您的库接受的字符,然后再将正文传递给解码器。
1 文档中有一条支持语句:the "raw" format 返回“作为 base64url 编码字符串的正文内容”。 (谢谢埃里克!)
【讨论】:
整体非常好,很有帮助,谢谢!请注意,关于第 2 点,它在 users.messages.get API 文档中提到:developers.google.com/gmail/api/v1/reference/users/messages/get(请参阅格式=RAW 文档)。但也许它应该进一步扩展...... 在找到您的有效解决方案之前,我已经检查了很多选项,谢谢!【参考方案2】:使用 atob 解码 javascript 中的消息(请参阅ref)。要访问您的消息负载,您可以编写一个函数:
var extractField = function(json, fieldName)
return json.payload.headers.filter(function(header)
return header.name === fieldName;
)[0].value;
;
var date = extractField(response, "Date");
var subject = extractField(response, "Subject");
引用自我之前的SO Question 和
var part = message.parts.filter(function(part)
return part.mimeType == 'text/html';
);
var html = atob(part.body.data);
如果上述内容不能 100% 正确解码,@cgenco 在下面这个答案中的 cmets 可能适用于您。在这种情况下,做
var html = atob(part.body.data.replace(/-/g, '+').replace(/_/g, '/'));
【讨论】:
看起来.replace(/-/g, '+').replace(/_/g, '/')
仍然需要完成才能正确解码。
@cgenco,感谢分享。你能解释一下为什么没有你的 replace
函数它是不够的吗?我很乐意修改我的答案。
根据@ento 的回答,Base64 编码varies across implementations,而谷歌恰好使用使用-
而不是+
和_
而不是/
的编码。【参考方案3】:
解决方法如下: Gmail API - “Users.messages: get” 方法响应 message.payload.body.data 将 base64 数据分开,用“-”符号分隔。它不是完整的 base64 编码文本,而是 base64 文本的一部分。您必须尝试解码其中的每个部分,或者通过联合制作一个单声道字符串并替换“-”符号。在此之后,您可以轻松地将其解码为人类文本。 您可以在这里手动检查每个部分https://www.base64decode.org
【讨论】:
【参考方案4】:我也对这一点感到恼火。我通过查看 VSCode 的扩展发现了一个解决方案。解决方法很简单:
const body = response.data.payload.body; // the base64 encoded body of a message
body = Buffer.alloc(
body.data.length,
body.data,
"base64"
).toString(); // the decoded message
当我使用 Gmail API 的 gmail.users.messages.get()
调用时,它对我有用。
【讨论】:
【参考方案5】:请使用网络安全解码器来解码 gmail 电子邮件和附件。当我只使用 base64decoder 时,我得到了空白页,不得不使用这个:https://www.npmjs.com/package/urlsafe-base64
【讨论】:
【参考方案6】:我可以使用https://simplycalc.com/base64-decode.php的另一个工具轻松解码
在 JS 中:https://www.npmjs.com/package/base64url
在 Python 3 中:
import base64
base64.urlsafe_b64decode(coded_string)
【讨论】:
【参考方案7】:感谢@ento 的回答。我进一步解释了为什么在解码之前需要将“-”和“_”字符替换为“+”和“/”。
Wiki Base64 Variants summary table 显示:
RFC 4648 第 4 节:base64(标准):使用“+”和“/” RFC 4648 第 5 节:base64url(URL 安全和文件名安全标准):使用“-”和“_”简而言之,Gmail API 使用 base64url (urlsafe) 格式('-' 和 '_'),但是 JavaScript atob 函数或其他 JavaScript 库使用 base64(标准)格式('+' 和 '/')。
对于Gmail API,文档说body使用base64url格式,见以下链接:
string/bytes type MessagePartBody RAW有关 Web atob/btoa 标准,请参见以下链接:
The algorithm used by atob() and btoa() is specified in RFC 4648, section 4 8.3 Base64 utility methods Forgiving base64【讨论】:
以上是关于Gmail API 在 Javascript 中解码消息的主要内容,如果未能解决你的问题,请参考以下文章
Gmail API - 使用 Javascript 解析邮件内容(Base64 解码?)
用于在节点 js javascript 文件中发送用户消息的 gmail API
在 Javascript 中使用 GMAIL API 发送带有附件文件(超过 10 MB)的电子邮件
收件人地址需要带有 JavaScript 的 gmail api