Gmail API 返回的 text/plain 内容编码存在差异
Discrepancy in text/plain content encoding returned by Gmail API
我正在尝试使用 GMail API 阅读 multipart/mixed
封电子邮件。
目标是将 multipart/mixed
电子邮件的每个 text/plain
部分(可以有很多,采用不同的编码)正确解码为 C# 字符串(即 UTF-16):
public static string DecodeTextPart(Google.Apis.Gmail.v1.Data.MessagePart part)
{
var content_type_header = part.Headers.FirstOrDefault(h => string.Equals(h.Name, "content-type", StringComparison.OrdinalIgnoreCase));
if (content_type_header == null)
throw new ArgumentException("No content-type header found in the email part");
var content_type = new System.Net.Mime.ContentType(content_type_header.Value);
if (!string.Equals(content_type.MediaType, "text/plain", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("The part is not text/plain");
return Encoding.GetEncoding(content_type.CharSet).GetString(GetAttachmentBytes(part.Body));
}
GetAttachmentBytes
returns 原始附件字节,未经转换,从 GMail 使用的 base64url encoding 解码。
我发现在很多情况下这会产生无效的字符串,因为我为附件内容获取的原始字节似乎总是采用 UTF-8,即使同一部分的 content-type
声明否则。
例如鉴于电子邮件:
Date: ...
From: ...
Reply-To: ...
Message-ID: ...
To: ...
Subject: Test 1 text file
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----------0E50FC0802A2FCCAA"
------------0E50FC0802A2FCCAA
Content-Type: text/plain; charset=windows-1251
Content-Transfer-Encoding: 8bit
Content test: Cyrillic, Windows-1251 (à, ÿ, æ)
------------0E50FC0802A2FCCAA
Content-Type: TEXT/PLAIN;
name="Irrelevant.txt"
Content-transfer-encoding: base64
Content-Disposition: attachment;
filename="Irrelevant.txt"
VGhpcyBmaWxlIGRvZXMgbm90IGNvbnRhaW4gdXNlZnVsIGluZm9ybWF0aW9u
------------0E50FC0802A2FCCAA--
,我成功找到了第一部分,上面的代码在 System.Net.Mime.ContentType
的帮助下计算出它是 charset=windows-1251
,然后是 .GetString()
returns 垃圾,因为实际GetAttachmentBytes
返回的原始字节对应于 UTF-8 编码,而不是 Windows-1251.
与
完全一样
Subject: Test 2 text file
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----------0B716C1D8123D8710"
------------0B716C1D8123D8710
Content-Type: text/plain; charset=koi8-r
Content-Transfer-Encoding: 8bit
Content test: Cyrillic, koi-8 (Б, С, Ц)
------------0B716C1D8123D8710
Content-Type: TEXT/PLAIN;
name="Irrelevant.txt"
Content-transfer-encoding: base64
Content-Disposition: attachment;
filename="Irrelevant.txt"
VGhpcyBmaWxlIGRvZXMgbm90IGNvbnRhaW4gdXNlZnVsIGluZm9ybWF0aW9u
------------0B716C1D8123D8710--
请注意,编码名称后括号中的三个测试字母在两封电子邮件中是相同的,在 Unicode 中看起来像 (а, я, ж)
,但(正确地)在上面引用的电子邮件正文表示中看起来是错误的不同的编码。
如果我 "fix" 始终使用 Encoding.UTF8
而不是 GetEncoding(content_type.CharSet)
的函数,那么它似乎在我到目前为止所做的测试中有效。
同时,GMail 界面在这两种情况下都能正确显示字母,因此它必须使用正确声明的编码正确解析传入的电子邮件。
GMail API 是否将所有文本块重新编码为 UTF-8(包装在 base64url 中),但为它们报告原始 charset
?
因此,我是否应该始终在 GMail API 中使用 UTF-8 而忽略 content-type
的 charset=
?
还是我的代码有问题?
根据这两个资源:
- Stack Overflow: Gmail API decoding messages in Javascript
- GitHub: Google API Python Client: Invalid message body size
该值确实是 转换为 UTF-8 部分的 base-64 编码表示。
据我所知,Google 并未对此进行记录。
我正在尝试使用 GMail API 阅读 multipart/mixed
封电子邮件。
目标是将 multipart/mixed
电子邮件的每个 text/plain
部分(可以有很多,采用不同的编码)正确解码为 C# 字符串(即 UTF-16):
public static string DecodeTextPart(Google.Apis.Gmail.v1.Data.MessagePart part)
{
var content_type_header = part.Headers.FirstOrDefault(h => string.Equals(h.Name, "content-type", StringComparison.OrdinalIgnoreCase));
if (content_type_header == null)
throw new ArgumentException("No content-type header found in the email part");
var content_type = new System.Net.Mime.ContentType(content_type_header.Value);
if (!string.Equals(content_type.MediaType, "text/plain", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("The part is not text/plain");
return Encoding.GetEncoding(content_type.CharSet).GetString(GetAttachmentBytes(part.Body));
}
GetAttachmentBytes
returns 原始附件字节,未经转换,从 GMail 使用的 base64url encoding 解码。
我发现在很多情况下这会产生无效的字符串,因为我为附件内容获取的原始字节似乎总是采用 UTF-8,即使同一部分的 content-type
声明否则。
例如鉴于电子邮件:
Date: ...
From: ...
Reply-To: ...
Message-ID: ...
To: ...
Subject: Test 1 text file
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----------0E50FC0802A2FCCAA"
------------0E50FC0802A2FCCAA
Content-Type: text/plain; charset=windows-1251
Content-Transfer-Encoding: 8bit
Content test: Cyrillic, Windows-1251 (à, ÿ, æ)
------------0E50FC0802A2FCCAA
Content-Type: TEXT/PLAIN;
name="Irrelevant.txt"
Content-transfer-encoding: base64
Content-Disposition: attachment;
filename="Irrelevant.txt"
VGhpcyBmaWxlIGRvZXMgbm90IGNvbnRhaW4gdXNlZnVsIGluZm9ybWF0aW9u
------------0E50FC0802A2FCCAA--
,我成功找到了第一部分,上面的代码在 System.Net.Mime.ContentType
的帮助下计算出它是 charset=windows-1251
,然后是 .GetString()
returns 垃圾,因为实际GetAttachmentBytes
返回的原始字节对应于 UTF-8 编码,而不是 Windows-1251.
与
完全一样Subject: Test 2 text file
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----------0B716C1D8123D8710"
------------0B716C1D8123D8710
Content-Type: text/plain; charset=koi8-r
Content-Transfer-Encoding: 8bit
Content test: Cyrillic, koi-8 (Б, С, Ц)
------------0B716C1D8123D8710
Content-Type: TEXT/PLAIN;
name="Irrelevant.txt"
Content-transfer-encoding: base64
Content-Disposition: attachment;
filename="Irrelevant.txt"
VGhpcyBmaWxlIGRvZXMgbm90IGNvbnRhaW4gdXNlZnVsIGluZm9ybWF0aW9u
------------0B716C1D8123D8710--
请注意,编码名称后括号中的三个测试字母在两封电子邮件中是相同的,在 Unicode 中看起来像 (а, я, ж)
,但(正确地)在上面引用的电子邮件正文表示中看起来是错误的不同的编码。
如果我 "fix" 始终使用 Encoding.UTF8
而不是 GetEncoding(content_type.CharSet)
的函数,那么它似乎在我到目前为止所做的测试中有效。
同时,GMail 界面在这两种情况下都能正确显示字母,因此它必须使用正确声明的编码正确解析传入的电子邮件。
GMail API 是否将所有文本块重新编码为 UTF-8(包装在 base64url 中),但为它们报告原始 charset
?
因此,我是否应该始终在 GMail API 中使用 UTF-8 而忽略 content-type
的 charset=
?
还是我的代码有问题?
根据这两个资源:
- Stack Overflow: Gmail API decoding messages in Javascript
- GitHub: Google API Python Client: Invalid message body size
该值确实是 转换为 UTF-8 部分的 base-64 编码表示。
据我所知,Google 并未对此进行记录。