表情符号未在 gmail 主题中呈现
Emoji is not rendered in the subject of gmail
我正在使用 GMAIL api 从 nodejs api 发送电子邮件。我正在使用以下实用函数
渲染原始 body
message += '[DEFAULT EMOJI ]'
const str = [
'Content-Type: text/html; charset="UTF-8"\n',
'MIME-Version: 1.0\n',
'Content-Transfer-Encoding: 7bit\n',
'to: ',
to,
'\n',
'from: ',
from.name,
' <',
from.address,
'>',
'\n',
'subject: ',
subject + '[DEFAULT EMOJI ]',
'\n\n',
message
].join('');
return Buffer.alloc(str.length, str).toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
我用来发送电子邮件的代码是
const r = await gmail.users.messages.send({
auth,
userId: "me",
requestBody: {
raw: makeEmailBody(
thread.send_to,
{
address: user.from_email,
name: user.from_name,
},
campaign.subject,
campaign.template,
thread.id
),
},
});
表情符号正在 body 中呈现,但在主题中不起作用。见下图
左边一个来自桌面 Google Chrome 中的 Gmail,右边一个来自移动
中的 Gmail 应用程序
您的实用程序可能会受益于多项改进(我们将讨论表情符号问题):
- 首先,使其成为 RFC822 compliant by separating lines with CRLF (
\r\n
).
- 小心
Content-Transfer-Encoding
header,将其设置为 7bit
最简单,但可能不够通用(quoted-printable 可能是更好的选择)。
现在是表情符号问题:
您需要确保主题已正确编码 与 body 分开 才能传递表情符号。根据 RFC13420,您可以对主题使用 Base64 或 quoted-printable 编码来创建 encoded-word,描述为:
"=" "?" charset "?" encoding "?" encoded-text "?" "="
其中 quoted-printable 编码为 Q
,Base64 编码编码为 B
。
请注意,生成的编码主题字符串的长度不得超过 76 个字符,这会为字符串保留 75 个字符,并且1 作为分隔符(要使用多个单词,用 space 或换行符 [CRLF 以及] 分隔它们)。
所以,将你的字符集设置为 utf-8
,编码为 Q
,用下面的内容对实际主题进行编码 1,你就成功了一半完成:
/**
* @summary RFC 1342 header encoding
* @see {@link https://www.rfc-editor.org/rfc/rfc1342}
*/
class HeaderEncoder {
/**
* @summary encode using Q encoding
*/
static quotedPrintable(str: string, encoding = "utf-8") {
let encoded = "";
for (const char of str) {
const cp = char.codePointAt(0);
encoded += `=${cp.toString(16)}`;
}
return `=?${encoding}?Q?${encoded}?=`;
}
}
现在,有趣的部分。我正在从事一个必须直接利用 Gmail API 的 GAS 项目(毕竟,这就是客户端库在幕后所做的事情)。即使使用正确的编码,尝试传递类似 "Beep! \u{1F697}"
的内容也会导致错误解析的主题。
事实证明,您需要利用 fromCodePoint
对原始字符串的字节数组或缓冲区进行操作。这个片段应该足够了(不要忘记只应用于多字节字符):
const escape = (u: string) => String.fromCodePoint(...Buffer.from(u));
0 这是最初的 RFC,更适合参考 RFC 2047. Also, see RFC 2231 在 header 中包含语言环境信息(以及更多晦涩的扩展名)。
1如果char落在printable US-ASCII的范围内,可以保留as-is,但由于规则比较多,我建议坚持48-57
(数字)、65-90
(大写)和 97-122
(小写)范围。
我正在使用 GMAIL api 从 nodejs api 发送电子邮件。我正在使用以下实用函数
渲染原始 bodymessage += '[DEFAULT EMOJI ]'
const str = [
'Content-Type: text/html; charset="UTF-8"\n',
'MIME-Version: 1.0\n',
'Content-Transfer-Encoding: 7bit\n',
'to: ',
to,
'\n',
'from: ',
from.name,
' <',
from.address,
'>',
'\n',
'subject: ',
subject + '[DEFAULT EMOJI ]',
'\n\n',
message
].join('');
return Buffer.alloc(str.length, str).toString('base64').replace(/\+/g, '-').replace(/\//g, '_');
我用来发送电子邮件的代码是
const r = await gmail.users.messages.send({
auth,
userId: "me",
requestBody: {
raw: makeEmailBody(
thread.send_to,
{
address: user.from_email,
name: user.from_name,
},
campaign.subject,
campaign.template,
thread.id
),
},
});
表情符号正在 body 中呈现,但在主题中不起作用。见下图
左边一个来自桌面 Google Chrome 中的 Gmail,右边一个来自移动
中的 Gmail 应用程序您的实用程序可能会受益于多项改进(我们将讨论表情符号问题):
- 首先,使其成为 RFC822 compliant by separating lines with CRLF (
\r\n
). - 小心
Content-Transfer-Encoding
header,将其设置为7bit
最简单,但可能不够通用(quoted-printable 可能是更好的选择)。
现在是表情符号问题:
您需要确保主题已正确编码 与 body 分开 才能传递表情符号。根据 RFC13420,您可以对主题使用 Base64 或 quoted-printable 编码来创建 encoded-word,描述为:
"=" "?" charset "?" encoding "?" encoded-text "?" "="
其中 quoted-printable 编码为 Q
,Base64 编码编码为 B
。
请注意,生成的编码主题字符串的长度不得超过 76 个字符,这会为字符串保留 75 个字符,并且1 作为分隔符(要使用多个单词,用 space 或换行符 [CRLF 以及] 分隔它们)。
所以,将你的字符集设置为 utf-8
,编码为 Q
,用下面的内容对实际主题进行编码 1,你就成功了一半完成:
/**
* @summary RFC 1342 header encoding
* @see {@link https://www.rfc-editor.org/rfc/rfc1342}
*/
class HeaderEncoder {
/**
* @summary encode using Q encoding
*/
static quotedPrintable(str: string, encoding = "utf-8") {
let encoded = "";
for (const char of str) {
const cp = char.codePointAt(0);
encoded += `=${cp.toString(16)}`;
}
return `=?${encoding}?Q?${encoded}?=`;
}
}
现在,有趣的部分。我正在从事一个必须直接利用 Gmail API 的 GAS 项目(毕竟,这就是客户端库在幕后所做的事情)。即使使用正确的编码,尝试传递类似 "Beep! \u{1F697}"
的内容也会导致错误解析的主题。
事实证明,您需要利用 fromCodePoint
对原始字符串的字节数组或缓冲区进行操作。这个片段应该足够了(不要忘记只应用于多字节字符):
const escape = (u: string) => String.fromCodePoint(...Buffer.from(u));
0 这是最初的 RFC,更适合参考 RFC 2047. Also, see RFC 2231 在 header 中包含语言环境信息(以及更多晦涩的扩展名)。
1如果char落在printable US-ASCII的范围内,可以保留as-is,但由于规则比较多,我建议坚持48-57
(数字)、65-90
(大写)和 97-122
(小写)范围。