Я экспериментирую с чтением multipart/mixed
писем с помощью GMail API.
Цель состоит в том, чтобы правильно декодировать каждую text/plain
часть письма multipart/mixed
(их может быть много в разных кодировках) в C# string (то есть 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
возвращает необработанные байты вложения без преобразования, декодированные из кодировки base64url , которую использует GMail.
Я обнаружил, что во многих случаях это приводит к неправильным строкам, потому что необработанные байты, которые я получаю для содержимого вложения, по-видимому, всегда находятся в 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--
, я успешно нахожу первую часть, код выше показывает, что она charset=windows-1251
с помощью System.Net.Mime.ContentType
, а затем .GetString()
возвращает мусор, потому что фактический необработанные байты, возвращаемые 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--
Обратите внимание, что три круглые буквы в скобках после кодировки NAM Они одинаковы в обоих письмах, и в Unicode выглядят как (а, я, ж)
, но (правильно) выглядят неправильно в представлении тела письма, приведенном выше, из-за различных кодировок.
Если я "исправлю" функцию, чтобы всегда используйте Encoding.UTF8
вместо GetEncoding(content_type.CharSet)
, тогда он работает в тестах, которые я до сих пор проводил.
В то же время интерфейс GMail правильно отображает буквы в обоих случаях, поэтому должен правильно проанализировать входящие электронные письма, используя правильные объявленные кодировки.
Это тот случай, когда API GMail перекодирует все текстовые блоки в UTF-8 (обернутый в base64url), но сообщает исходный charset
для них?
Поэтому я должен всегда использовать UTF-8 с GMail API и игнорировать content-type
charset=
?
Или есть проблема с моим кодом?