Michael Haephrati Ответов: 2

Как интерпретировать необработанные данные gmail


Я пытаюсь выяснить, как анализировать необработанные данные электронной почты Gmail и сохранять ее элементы (т. е. тело, тему, дату и вложения). Я нашел примеры кода для разбора многосоставных данных, которые, как мне кажется, можно использовать.

Необработанные Данные Gmail - Смотрите это объяснение[^]

То, что я ищу, - это конкретное решение для необработанных данных Gmail, являющееся сложным примером MIME, имеющим несколько типов встроенных элементов (изображения, HTML / rich text, вложения). Моя цель - извлечь эти элементы и хранить их отдельно. Я ищу не интерактивный протокол, такой как POP3, а статический, что означает, что с помощью этих необработанных данных можно получить всю электронную почту вместе с ее элементами даже в автономном режиме.

IDE - я использую Visual Studio Ultimate, C++ вместе с Win32 API.

Что я уже пробовал:

Например эта статья[^] похоже, у него есть строительные блоки для разбора такой электронной почты. Однако я ищу решение, посвященное таким необработанным данным, так как этот тип данных довольно сложен, объединяя различные элементы, вложения, все в одном файле (или блоке данных).


Вот мой текущий код.

LPCSTR szMailId, LPCSTR szMailBody;
MIMELIB::CONTENT c;
while ((*szMailBody == ' ') || (*szMailBody == '\r') || (*szMailBody == '\n'))
{
    szMailBody++;
}
char deli[] = "<pre class=\"raw_message_text\" id=\"raw_message_text\">";
szMailBody = strstr(szMailBody, deli);
szMailBody += strlen(deli);

CStringA Body = szMailBody;
Body = Body.Left(Body.Find("<//pre><//div><//div><//div><//body><//html>"));
Body = Body.Mid(Body.Find("<html>"));

szMailBody = Body.GetString();
if (c.Parse(szMailBody) != MIMELIB::MIMEERR::OK)
    return;
// Get some headers
auto senderHdr = c.hval("From");
string strDate = c.hval("Date");    // Example Sat, 13 Jan 2018 07:54:39 -0500 (EST)
auto subjectHdr = c.hval("Subject");

auto a1 = c.hval("Content-Type", "boundary");
// Not a multi-part mail if empty
// Then use c.Decode() to get and decode the single part body
if (a1.empty())
    return;
vector<MIMELIB::CONTENT> Contents;
MIMELIB::ParseMultipleContent2(szMailBody, strlen(szMailBody), a1.c_str(), Contents);

int i;
for (i = 0; i < Contents.size(); i++)
{
    vector<char> d;
    string type = Contents[i].hval("Content-type");
    d = Contents[i].GetData(); // Decodes from Base64 or Quoted-Printable
}

2 Ответов

Рейтинг:
14

Jochen Arndt

В дополнение к вашей теме в упомянутой статье, которая, кажется, решила вашу проблему и имеет ответ здесь:

Нет никаких конкретных "сырых" данных Gmail. Это формат почтовых сообщений, определенный RFC 2822: формат интернет-сообщений[^] и связанные с ними RFC, такие как RFC 2045 - 2049 для расширений MIME.

Эти RFC содержат необходимую информацию для написания синтаксического анализатора.

[РЕДАКТИРОВАТЬ]
Пример кода с использованием mimelib.ч файл из упомянутой статьи. Скомпилирован и протестирован с помощью VS 2017. Требует /Zc:strictStrings-.

#include "stdafx.h"

#include <windows.h>
#include <WinInet.h>
#include <string>
#include <sstream>
#include <vector>
#include <memory>
#include <intrin.h>

using namespace std;

#include "mimelib.h"

#pragma comment(lib, "crypt32")

MIMELIB::MIMEERR ParsePart(MIMELIB::CONTENT& c, const char* szPart = "")
{
    MIMELIB::MIMEERR merr = MIMELIB::MIMEERR::OK;
    auto boundary = c.hval("Content-Type", "boundary");
    // Single part
    if (boundary.empty())
    {
        std::string strPart = (szPart && *szPart) ? szPart : "1";
        auto typeHdr = c.hval("Content-Type");
        if (typeHdr.empty())
        {
            wprintf(L"Part %hs: Default (single)\n", strPart.c_str());
            typeHdr = "text/plain;";
        }
        else
        {
            wprintf(L"Part %hs: %hs\n", strPart.c_str(), typeHdr.c_str());
        }
        auto fileName = c.hval("Content-Disposition", "filename");
        if (fileName.empty())
        {
            // Create a file name from part and an extension that matches the content type
            std::string ext = "txt";
            auto subTypeS = typeHdr.find('/');
            auto subTypeE = typeHdr.find(';');
            if (subTypeS > 0 && subTypeE > subTypeS)
            {
                subTypeS++;
                ext = typeHdr.substr(subTypeS, subTypeE - subTypeS);
            }
            if (ext == "plain")
                ext = "txt";
            else if (ext == "octet-stream")
                ext = "bin";
            fileName = "Part";
            fileName += strPart;
            fileName += '.';
            fileName += ext;
        }
        // Get the decoded body of the part
        vector<char> partData;
        c.DecodeData(partData);
        // TODO: Decode fileName if it is inline encoded
        FILE *f;
        errno_t err = fopen_s(&f, fileName.c_str(), "wb");
        if (err)
        {
            char errBuf[128];
            strerror_s(errBuf, err);
            fwprintf(stderr, L" Failed to create file %hs: %hs\n", fileName.c_str(), errBuf);
        }
        else
        {
            fwrite(partData.data(), partData.size(), 1, f);
            fclose(f);
            wprintf(L" Saved part to file %hs\n", fileName.c_str());
        }
    }
    else
    {
        // Decoded part of mail (full mail with top level call)
        auto data = c.GetData();
        // Split it into the boundary separated parts 
        vector<MIMELIB::CONTENT> Contents;
        merr = MIMELIB::ParseMultipleContent2(data.data(), data.size(), boundary.c_str(), Contents);
        if (MIMELIB::MIMEERR::OK == merr)
        {
            int part = 1;
            for (auto & cp : Contents)
            {
                std::string strPart;
                if (szPart && *szPart)
                {
                    strPart = szPart;
                    strPart += '.';
                }
                char partBuf[16];
                _itoa_s(part, partBuf, 10);
                strPart += partBuf;
                ParsePart(cp, strPart.c_str());
                ++part;
            }
        }
    }
    return merr;
}

int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        fwprintf(stderr, L"Usage: ParseMail <file>\n");
        return 1;
    }
    struct _stat st;
    if (_stat(argv[1], &st))
    {
        fwprintf(stderr, L"File %hs not found\n", argv[1]);
        return 1;
    }
    FILE *f = NULL;
    errno_t err = fopen_s(&f, argv[1], "rb");
    if (err)
    {
        char errBuf[128];
        strerror_s(errBuf, err);
        fwprintf(stderr, L"File %hs can't be opened: %hs\n", argv[1], errBuf);
        return 1;
    }
    char *buf = new char[st.st_size + 1];
    fread(buf, 1, st.st_size, f);
    buf[st.st_size] = 0;
    fclose(f);

    MIMELIB::CONTENT c;
    MIMELIB::MIMEERR merr = c.Parse(buf);
    if (merr != MIMELIB::MIMEERR::OK)
    {
        fwprintf(stderr, L"Error pasing mail file %hs\n", argv[1]);
    }
    else
    {
        auto senderHdr = c.hval("From");
        auto dateHdr = c.hval("Date");
        auto subjectHdr = c.hval("Subject");
        wprintf(L"From: %hs\n", senderHdr.c_str());
        wprintf(L"Date: %hs\n", dateHdr.c_str());
        wprintf(L"Subject: %hs\n\n", subjectHdr.c_str());
        merr = ParsePart(c);
    }
    delete[] buf;
    return merr;
}

Пример вывода для составного письма:
From: [redacted]
Date: Tue, 26 Sep 2017 09:44:15 +0200
Subject: =?ISO-8859-1?Q?WG=3A_Haftverzichtserkl=E4rung_f=FCr_[...]_Fa=2E_S
iS?=; =?ISO-8859-1?Q?_-_EMB_168_-_12=2E10=2E2017?=

Part 1.1: text/plain; charset="UTF-8"
 Saved part to file Part1.1.txt
Part 1.2: text/html; charset="UTF-8"
 Saved part to file Part1.2.html
Part 2: application/octet-stream; name="HaVerzSiS.pdf"
 Saved part to file HaVerzSiS.pdf
Part 3: image/jpeg; name="Liegeplatz FS EMB.jpg"
 Saved part to file Liegeplatz FS EMB.jpg
[/РЕДАКТИРОВАТЬ]


Michael Haephrati

К сожалению, нить переписки не решила мою проблему. Итак, не могли бы вы указать мне пример исходного кода для синтаксического анализа этого формата? (RFC 2822: формат интернет-сообщений)

Jochen Arndt

Мне тоже пришлось искать его, но "c++ mime parser" получает много результатов. Я бы искал хорошо известную / часто используемую библиотеку.

Я предлагаю также расширить код из статьи, чтобы знать, где происходит сбой синтаксического анализа. Возможно, ваша почта не очень хорошо сформирована (маловероятно, потому что на нее будет жаловаться почтовый клиент), код статьи не соответствует RFC или не поддерживает определенную часть, используемую вашей почтой.

Вы также можете добавить неудачный почтовый контент в свой вопрос (анонимизированный и с укороченными строками данных MIME = только первая и последняя строка) и/или в статью. Тогда я и другие могут посмотреть.

Michael Haephrati

Речь идет не о конкретной почте, а в целом, и я читаю письма непосредственно с нее. gmail.com-да. Если вы используете gmail, вы можете попробовать с любым сообщением gmail и посмотреть.

Jochen Arndt

Возможно, это проблема использования кода статьи и/или получения содержимого почты. Вы должны передать его как есть (std::string). То есть: никаких преобразований для линейных каналов (должно быть CR-LF) или кодировок символов (должно быть 7/8 бит).

Например, сохраните содержимое в файл и проверьте его с помощью текстового и/или шестнадцатеричного редактора. Если все выглядит нормально, считайте файл в буфер char [], добавьте нулевой байт и назначьте его строке std::. Тогда это должно сработать. Если нет, то вам следует спросить еще раз в статье форума.

Michael Haephrati

Если я сохраню данные в файл и назову его test.html, это будет показано должным образом. Могу ли я нанять вас частным образом для выполнения такой работы?

Jochen Arndt

Вы сохранили полный HTML-источник веб-сайта. Вы должны сохранить только часть почтового сообщения.

Сделайте это, выбрав и скопировав почтовое сообщение в браузере, вставив его в текстовый редактор и сохранив в файл.

Но его также может потребоваться сократить, поскольку он содержит также строки доставки SMTP. Таким образом, вы можете использовать существующий HTML-файл:

Откройте его с помощью текстового редактора и вырежьте все ненужные строки или выделите сообщение и вставьте в новую рамку редактора.

Часть, которая будет использоваться, находится внутри

<pre class="raw_message_text" id="raw_message_text">

метка.

Затем удалите все ведущие строки перед первой строкой заголовка
"Дата: Вт, 09 Янв 2018 12:07:03 +0000"

Вышеприведенный шаг может быть и не нужен, Но он дает вам окончательное простое содержание сообщения.

Jochen Arndt

Вам нужен простой полный текст сообщения, потому что именно он должен быть передан синтаксическому анализатору.

Загрузите содержимое файла в строку std::и проанализируйте ее, как показано в примерах синтаксического анализа в этой статье:

MIMELIB::CONTENT c;
if (c.Parse(str.c_str()) != MIMELIB::MIMEERR::OK)
    return;
// Get some headers
auto senderHdr = c.hval("From");
auto dateHdr = c.hval("Date");
auto subjectHdr = c.hval("Subject");


Затем разберите составные разделы как описано в статье:

auto a1 = c.hval("Content-Type","boundary");
// Not a multi-part mail if empty
// Then use c.Decode() to get and decode the single part body
if (a1.empty())
    return;
vector<MIMELIB::CONTENT> Contents;
MIMELIB::ParseMultipleContent(str.c_str(), a1.c_str(), Contents);
// Body mail parts are now in Contents
// Check type with Contents[ndx].hval("Content-type")
// Use Contents[ndx].Decode() to get a byte array with decoded data
//  like binary for binary attachments or usually UTF-8 for text / HTML


Кстати: это не мой код. Поэтому вам следует обратиться на форум статей за помощью, связанной с кодом статьи.

Michael Haephrati

Спасибо. Вы должны использовать ParseMultipleContent2 (), а не ParseMultipleContent (), который комментируется в исходном коде... Правильно?

Michael Haephrati

Можете ли вы привести мне пример того, как будет закодировано вложение и как его извлечь?

Jochen Arndt

Честно говоря, я не читал источник. Я только что прочитал статью, и там нет функции ParseMultipleContent2 ().

Чтобы получить вложение, вызовите Decode (), когда оно закодировано Base64 или QuotedPrintable (что обычно и происходит, за исключением 7-битного текста). Функция Decode() проверит, какая кодировка используется, изучив заголовок "Content-encoding". Затем запишите содержимое вектора char в файл.

Для вложений файлов существует заголовок "Content-disposition: attachment", который обычно содержит параметр "filename".

Для других частей это зависит от вас, чтобы выбрать имя файла. Вы можете использовать заголовок "Content-type", чтобы определить тип и выбрать соответствующее расширение, например .txt или .html.

дополнительное Примечание:
Этот (и большинство парсеров) использует те же функции для обработки почтовой части. Это позволяет анализировать многоуровневые вложенные письма. Это означает, что каждый раздел с несколькими частями (вектор содержимого из примеров) также может содержать несколько частей. Это произойдет, например, если у вас есть письмо с альтернативным текстом (обычный текст и HTML) и одним или несколькими вложениями файлов:
- Уровень 1: заголовок почты, составной/смешанный
- Уровень 2: часть 1.1: составная часть/альтернатива (только заголовки)
- Уровень 3: Часть 1.1.1: текст/обычный текст
- Уровень 3: Часть 1.1.2: текст/html
- Уровень 2: Часть 1.2: [тип MIME], содержание-диспозиция: вложение
- Уровень 2: часть 1.3: [тип MIME], содержание-диспозиция: вложение
...

Michael Haephrati

Я добавил этот код

вектор<mimelib::содержание> содержание;
MIMELIB::ParseMultipleContent2(Body,strlen(a1.c_str()), a1.c_str(), Contents);
// Части почты тела теперь находятся в содержимом
// Проверить тип с содержимым[ndx].hval("Content-type")
// Используйте содержимое[ndx].Декодировать (), чтобы получить байтовый массив декодированных данных
// like binary для бинарных вложений или обычно UTF-8 для текста / HTML

int i;
for (i = 0; i < Contents.size(); i++)


Однако он не попадает в петлю, как будто содержимое пусто..

Jochen Arndt

Я быстро просмотрел источники, и мне кажется, что вместо этого вы должны передать размер тела (Body.length ()) (вы передаете длину граничной строки).

Я предлагаю попросить автора статьи обновить свою статью, потому что статья не соответствует предоставленному коду и не объясняет параметр sz (даже не в источниках).

Michael Haephrati

Спасибо за вашу помощь. Автор не ответил, и действительно, его код мало что объясняет.
После изменения кода на
вектор<mimelib::содержание> содержание;
MIMELIB::ParseMultipleContent2(тело,тело.Метода getlength может служить метод(), А1.c_str(), содержание);
Я все еще получаю пустой вектор

Jochen Arndt

Используйте отладчик для проверки переменных.
Тело должно быть полным текстом письма, а a1.c_str-граничной строкой.
Функция синтаксического анализа просто получает содержимое между соответствующими граничными строками, применяет его к объекту содержимого и помещает этот объект в вектор.

Michael Haephrati

Йохен, я принял ваш ответ, но теперь хочу отклонить его (извините), чтобы другие представили ответы, которые, как мы надеемся, будут более сфокусированы на этом конкретном типе данных (необработанные данные Gmail). Для этого конкретного типа могут существовать библиотеки / фрагменты кода.

Jochen Arndt

Это ваше решение.

Но как уже объяснялось:
Нет никакого конкретного формата почты Gmail. Это тот же формат, который используется всеми другими почтовыми службами. Есть только определенные строки заголовка Gmail, которые были добавлены во время обработки сообщений. Но даже они соответствуют упомянутым RFC (в противном случае они были бы отклонены другими почтовыми системами).

Вы получаете содержимое почты из браузера с помощью веб-интерфейса Gmail. Затем вы должны отфильтровать содержимое сообщения. Незнание этого было вашей первоначальной проблемой (и вышло только во время этого обсуждения). Более профессиональное решение будет использовать IMAP или POP-клиент для получения содержимого почты.

Michael Haephrati

Речь идет не о формате, а о практическом способе преобразования необработанных данных Gmail для своих нуждающихся. Вот о чем мой вопрос. Вы писали об интерактивных протоколах для связи с сервером Gmail, но я думаю, что с необработанными данными можно было бы конвертировать эти данные в содержимое электронной почты без такого взаимодействия, например, находясь в автономном режиме. Так ли это?

Jochen Arndt

Поэтому вы должны сначала определить "необработанные данные" и как их получить.

Письма в формате объясняться может ответить. Почтовые клиенты создают их в этом формате, и серверы будут хранить их в том же формате (как и почтовые клиенты в своих локальных папках).

"Моя цель-извлечь эти элементы и хранить их отдельно".
Затем вам нужно сначала получить почту в стандартизированном формате, а затем разобрать ее с помощью собственного кода или любой из множества доступных библиотек.

Это две задачи.

Я не могу помочь с первым, потому что вы не определили его четко (кроме того, что делаете это вручную с помощью веб-клиента Gmail). Но вам нужен какой-то почтовый клиент с аутентификацией, чтобы получать письма, если это должно быть сделано программой.

Вторая задача-просто использовать библиотеку синтаксического анализа или написать свою собственную на основе RFC (их иногда трудно прочитать, но синтаксический анализ-это просто интерпретация обычного текста и необязательное декодирование).

Michael Haephrati

Определение находится здесь https://www.electrictoolbox.com/gmail-view-raw-email-message/
Как я вижу, в тот момент, когда у вас есть полные необработанные данные, вам не нужно никакого взаимодействия с серверами Gmail, и вы можете делать это в автономном режиме. Вся информация уже содержится в исходных данных. Я думаю, что речь идет о 2-м задании. Только не 1-й.

Jochen Arndt

Это не определение. Это статья, в которой описывается, как просматривать содержимое обычной почты с помощью веб-интерфейса Gmail.

Если вы делаете это вручную, вам просто нужно сделать то, что я уже объяснил:
- Храните его в файле, чтобы он мог быть загружен вашим приложением
- Передайте его парсеру

Все, что вам нужно заметить, это допустимая 7-битная строка содержимого почты (но большинство парсеров поддерживают 8-битное содержимое тела и, по крайней мере, терпимы к потоку строк).

Так что еще раз:
Попробуйте заставить используемую библиотеку работать (что может потребовать некоторой отладки) или выбрать другую, ищущую в интернете что-то вроде "c++ mime parser".

Такие Парсеры также являются неотъемлемой частью любой почтовой клиентской программы. Таким образом, код синтаксического анализа также можно найти в источниках почтовых клиентов с открытым исходным кодом.

Если у вас возникли проблемы с конкретной библиотекой, первое, что нужно сделать, это проверить свою почту, а затем связаться с автором (желательно с помощью прикрепленного форума).

Краткий обзор формата почты:

Строка заголовка:
FILED_NAME: FIELD_CONTENT [в сложенном виде: отступ продолжение кода crlf] эти символы не экранируются
Они должны быть 7-битными / US_ASCII (при необходимости используйте цитируемую печатную или встроенную кодировку base64).

Пустая завершающая строка CRLF в качестве разделителя после строк заголовка.

Тело:
Одинарная или многосоставная часть, где многосоставная часть обозначается соответствующими заголовками. Это может быть 8-битный текст, если он задан соответствующим заголовком. Существует ограничение на длину строки, и последняя строка должна быть завершена CRLF.

Тело может содержать несколько частей. Затем каждая деталь снова состоит из строк заголовка, пустой строки и тела детали в соответствии с теми же правилами, которые описаны выше.

Michael Haephrati

Можете ли вы поделиться здесь (в качестве ответа) рабочим примером этого? Сохранение буфера в файл и его загрузка не являются жизненно важными для целей объяснения. Просто просматривая этот буфер и анализируя его, показывая, что действительно, как я и предполагал, вся необходимая информация будет инкапсулирована в исходные данные.Ожидаемым ответом будет исходный код, вставленный сюда. Это не обязательно должен быть полный проект, но он, безусловно, может продемонстрировать, как извлекаются ключевые элементы (например, встроенное изображение в теле письма или вложение).

Jochen Arndt

Мне понадобится по крайней мере день, чтобы написать очень простой почтовый парсер, который может извлекать вложения. Но в этом нет необходимости, потому что существует много существующего (и проверенного!) кода, делающего это.

Вы смотрели некоторые, как между тем http://www.codesink.org/mimetic_mime_library.html ?

Michael Haephrati

Вперед! такие сторонние библиотеки охватывают слишком много (193 файла), в то время как решение этой конкретной проблемы (разбор необработанных данных gmail) и только его, не существует и может вместить несколько файлов, если вы создадите минимальное решение.

Jochen Arndt

Почему я должен тратить целый день или больше на то, что мне самому не нужно?

Вы должны быть в состоянии сделать это самостоятельно в соответствии с вашими публикациями. Это "просто" синтаксический анализ текста с использованием находок и/или регулярных выражений после прочтения и понимания RFC (при использовании существующих источников для декодирования QP и Base64).

Чтобы быть опубликованным, нужно потратить больше времени на тестирование и создание толерантного кода, потому что почта иногда не совсем соответствует RFC.

Наконец, должно быть просто заставить код из статьи работать (если есть проблема с кодом, а не с вводом) и адаптировать его к вашим потребностям.

Michael Haephrati

Хорошо. Я понимаю. Я постараюсь упаковать свой код во что-то, что я могу просто опубликовать здесь

Michael Haephrati

Я обновил вопрос с моим недавним исходным кодом. Этот исходный код исходит из того, что szMailBody содержит необработанные данные электронной почты и использует mimelib (https://www.codeproject.com/KB/cpp/1114232/mimelib.zip ) я пытаюсь извлечь из необработанных данных все элементы (встроенные изображения, HTML-тело, вложения и т. д.), предполагая, что это можно сделать статически, то есть без необходимости какого-либо взаимодействия с сервером Gmail.
Проблема в том, что я ожидаю, что содержимое будет содержать все элементы, но это не так.

Jochen Arndt

Это не сработает по двум причинам:
1. входные данные все еще содержат закрытие </pre> тег, который может быть проблемой для парсера.
2. Вы передаете c2 вместо c1 в ParseMultipleContent2().

Там также нет необходимости использовать c.Parse(Body.GetBuffer()). Просто использовать GetString() вместо этого потому что Parse()/code> argument is a <code>const char*. Или использовать std::string вместо а CStringA Или просто пройти мимо szMailBody когда нулевой Терминатор был записан в позиции закрытия </pre> метка.

То hval() функция возвращает содержимое поля заголовка, где версия с двумя аргументами возвращает только содержимое переданной подчасти.

Это значит, что c.hval("Content-Type","boundary") возвращает граничную строку, которая затем передается синтаксическому анализатору для разделения тела на граничные разделенные части.

Michael Haephrati

Я последовал Вашим комментариям и обновил код в своем вопросе.
Мне все еще нужна ваша помощь в реализации этого:
"Функция hval() возвращает содержимое поля заголовка, где версия с двумя аргументами возвращает только содержимое переданной подчасти.

Это означает, что c.hval("Content-Type","boundary") возвращает граничную строку, которая затем передается синтаксическому анализатору для разделения тела на граничные разделенные части."
Не совсем понимаю, что ты имеешь в виду...

Jochen Arndt

Просто проверьте возвращаемые строки и сравните их с содержимым почты. Взгляните также на код функции, чтобы узнать, что делает эта функция.

Body = Body.Mid(Body.Find("<html>"));
Какова цель этой линии?
Если почта содержит HTML-часть, она будет вырезать только ее, чтобы у вас больше не было действительного почтового сообщения.

Michael Haephrati

Я хочу отметить Ваш ответ как принятый. Я все еще не понимаю последние 2 абзаца в вашем предыдущем комментарии.

Функция hval() возвращает содержимое поля заголовка, где версия с двумя аргументами возвращает только содержимое переданной подчасти.

Это означает, что c.hval("Content-Type","boundary") возвращает граничную строку, которая затем передается синтаксическому анализатору для разделения тела на граничные разделенные части.


Не могли бы вы показать мне, как добавить эту часть в мой код?

Jochen Arndt

В этих параграфах объясняется, что делают функции hval (). hval-это аббревиатура от HeaderValue. Они возвращают содержимое поля заголовка почты, где функция с одним параметром (имя поля заголовка) возвращает полное содержимое, а другая-только ту часть содержимого, которая соответствует второму параметру.

Взгляните на содержимое почты (раздел заголовка в начале) и сравните его со значениями, возвращаемыми вызовами функции hval ().

MarkSwift2018

Можете ли вы опубликовать здесь полное решение (с исходным кодом)?

Jochen Arndt

См. обновленный ответ.

Michael Haephrati

Йохен, пожалуйста, опубликуйте фрагмент кода с вашим решением. Это должен быть не полный проект, а только та часть, которая обсуждалась здесь, но как полный блок кода (если можно). Спасибо!

Jochen Arndt

См. обновленный ответ.

Рейтинг:
1

Richard MacCutchan

Вот копия типичного сообщения Gmail (интересно от вас):

Delivered-To: anonymousnam AT gmail.com
Received: by 10.2.15.201 with SMTP id 70csp1706370jao;
        Fri, 12 Jan 2018 02:08:02 -0800 (PST)
X-Google-Smtp-Source: ACJfBovDfSZaL48gp2hiXRdWrkQ2fN4ADImypAfgO6nn3bL9YXe9pyOS1NCsj6nejU8n0AFGoP8W
X-Received: by 10.107.140.78 with SMTP id o75mr23661888iod.219.1515751682675;
        Fri, 12 Jan 2018 02:08:02 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1515751682; cv=none;
        d=google.com; s=arc-20160816;
        b=Wronqhb0qgSWSapehG2PSI00FvI+Y2o3/MG8O6czKU/v9/9ETX4ObQ6hBP4fzRoAko
         U8mhgMZqhMoIKVv7czqG2g0S/VxBBkmPNUv7JbLZdZISzsO9e46SdfbhSKJMEdrESxtW
         7tankKOzdVFh5kbOX0ZWJrrCO1/a15lEo5MBChjr0apydxskoXq7p2vNmafiC9pqKads
         jNK2+Pkc0Y2OeEfL67Vs8IlXN+u1y2TYn9A8uZbfdNmPL6zq3rJ31v9hDdyXM3p3oTg4
         YP0K1+el4JFRgF4zo0Pyg4gFl62QzIv/SfP12o6ihsOIJZ68eS7PoDHYfZvKQXLySAjH
         2l2w==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=content-transfer-encoding:subject:date:to:from:mime-version
         :message-id:arc-authentication-results;
        bh=8sfAQGYMvxQ7PtXZ5Em7odijeBxnxUxWk1qh7LONjxM=;
        b=xHGbZSMYY74D6WFzT2SVpmOjKqALpbjgEopoaeGKE+2mUj77Is+gvHb/Q81aFnvjDY
         0xPKbsKUM6vPYCO9FU9QFumqP/XrYxEVQ5EOzxFk0SGV18QuzLGTkIxTVz97ARYLpnII
         M/gvPlSNX8hUfyzjh/0NsiD/64FMoCmLanRA0aQb+73TUHcKKwIEMhbwgQ9xizvShBKz
         hCMWDz92D6qhTI5Dhhfzjy/xm4j4TTNQxAW5rOgdm5LFg22tgTdkhenGSWUMtgOalstY
         0r4he7xoor6Ut0rT3QBZKr+5kywuyi3XZGVUmXvwKtss3ChDGcL4xqwos4HUzsW6i8YP
         1GFw==
ARC-Authentication-Results: i=1; mx.google.com;
       spf=pass (google.com: domain of anonymousnam AT codeproject.com designates 76.74.234.221 as permitted sender) smtp.mailfrom=anonymousnam AT codeproject.com
Return-Path: <anonymousnam AT odeproject.com>
Received: from mail.notifications.codeproject.com (mail.notifications.codeproject.com. [76.74.234.221])
        by mx.google.com with ESMTPS id l64si3747147iof.279.2018.01.12.02.08.02
        for <anonymousname AT gmail.com>
        (version=TLS1 cipher=AES128-SHA bits=128/128);
        Fri, 12 Jan 2018 02:08:02 -0800 (PST)
Received-SPF: pass (google.com: domain of anonymousname AT codeproject.com designates 76.74.234.221 as permitted sender) client-ip=76.74.234.221;
Authentication-Results: mx.google.com;
       spf=pass (google.com: domain of anonymousname AT codeproject.com designates 76.74.234.221 as permitted sender) smtp.mailfrom=anonymousname AT codeproject.com
Message-Id: <5a588902.43bb6b0a.f549b.f8cdSMTPIN_ADDED_MISSING@mx.google.com>
Received: from CP-WEB2 (cp-web2.codeproject.com [192.168.5.52]) by mail.notifications.codeproject.com (Postfix) with ESMTP id 2FB2E1E0DE8 for <anonymousname AT gmail.com>; Fri, 12 Jan 2018 04:55:19 -0500 (EST)
MIME-Version: 1.0
From: CodeProject Answers <anonymousname AT codeproject.com>
To: anonymousname AT gmail.com>
Date: 12 Jan 2018 05:08:01 -0500
Subject: CodeProject | A reply was posted to your comment
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.=
w3.org/TR/html4/loose.dtd"><html><head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dus-ascii"=
>
<meta name=3D"viewport" content=3D"width=3Ddevice-width">
</head><body style=3D"background-color: white;font-size: 14px; font-family:=
 'Segoe UI', Arial, Helvetica, sans-serif">
<style type=3D"text/css">
body,table,p,div { background-color:white; }
body,table,p,div { background-color:white; }
body, td, p,h1,h2,h6,h3,h4,li,blockquote,div{ font-size:14px; font-family: =
'Segoe UI', Arial, Helvetica, sans-serif; } =20
h1 {font-size: 26px; font-weight: bold; color: #498F00; margin-bottom:5px;m=
argin-top:0px;} =20
h2 { font-size: 24px; font-weight: 500; }
h4 { font-size: 16px; }
h3 {font-size: 11pt; font-weight:bold;} =20
h6 {font-size:6pt;color:#666;margin:0;} =20
table =09=09=09{ width: 100%;} =20
table.themed =09{ background-color:#FAFAFA; } =20
a =09=09=09=09{ text-decoration:none;} =20
a:hover =09=09{ text-decoration:underline;} =20
.tiny-text=09=09{ font-size: 12px; }
.desc =09=09=09{ color:#333333; font-size:12px;}
.themed td  =09{ padding:2px; } =20
.themed .alt-item { background-color:#FEF9E7; } =20
.header =09=09{ font-weight:bold; background-color:#FF9900; vertical-align:=
middle;} =20
.footer =09=09{ font-weight:bold; background-color: #488E00; color:White; v=
ertical-align:middle; }
.signature =09=09{ border-top: solid 1px #CCCCCC; padding-top:0px; margin-t=
op:10px; max-height:150px; overflow:auto;}

.content-list=09=09{ margin-bottom: 17px;}
.content-list-item=09{ margin:     10px 0; }
.doctype img=09=09{ vertical-align:bottom; padding-right:3px;}
.entry=09=09=09    { font-size: 14px; line-height:20px; margin: 0;}
.title=09=09=09    { font-size: 16px; font-weight:500; padding:0; }
.entry=09=09=09=09{ font-size: 14px; color:#666; }
.author, .author a  { font-size: 11px; font-weight:bold; }
.location=09=09    { font-size: 11px; font-weight:bold; color: #999}
.summary            { font-size: 12px; color: #999; padding: 0px 0 10px; }
.theme-fore         { color: #f90; }
.theme-back         { background-color: #f90; }
</style>
<table cellspacing=3D"1" cellpadding=3D"3" class=3D"header" border=3D"0" st=
yle=3D"background-color: #FF9900;width: 100%;font-weight: bold;vertical-ali=
gn: middle"><tbody><tr><td style=3D"font-size: 14px; font-family: 'Segoe UI=
', Arial, Helvetica, sans-serif">
<img border=3D"0" src=3D"https://www.codeproject.com/App_Themes/CodeProject=
/Img/logo225x40.gif" width=3D"225" height=3D"40"></td></tr></tbody></table>

<p style=3D"background-color: white;font-size: 14px; font-family: 'Segoe UI=
', Arial, Helvetica, sans-serif">Michael Haephrati has pos=
ted a reply to your comment about=20
"<a href=3D"https://www.codeproject.com/Answers/1224946/Conversion-to-Unico=
de-Cplusplus-Microsoft-UTF-Nati?cmt=3D969334#cmt969334" style=3D"text-decor=
ation: none">Conversion to Unicode (C++, Microsoft, UTF-16, Native Windows)=
</a>":</p>=20

<blockquote style=3D"font-size: 14px; font-family: 'Segoe UI', Arial, Helve=
tica, sans-serif">Apparently there is no expiration date to questions and w=
hen I looked for unanswered questions, I got here...</blockquote>

<hr class=3D"divider" noshade=3D"noshade" size=3D"1">
<div style=3D"background-color: white;font-size: 14px; font-family: 'Segoe =
UI', Arial, Helvetica, sans-serif"><a href=3D"https://www.codeproject.com" =
style=3D"text-decoration: none">CodeProject</a></div>
<div class=3D"small" style=3D"background-color: white;font-size: 14px; font=
-family: 'Segoe UI', Arial, Helvetica, sans-serif">Note: T=
his message has been sent from an unattended email box.</div>
</body></html>

Таким образом, вы можете видеть, что заголовки сообщений-это метки управления, за которыми следует двоеточие. Начало текста сообщения отделяется от заголовков пустой строкой и может быть форматированным текстом, HTML или обычным текстом. В почтовом RFC перечислены все возможные имена меток заголовков.


Jochen Arndt

Теперь мы и комбайнов, запустить по спамерам узнать ваш адрес Gmail.

Вы должны сделать их обоих анонимными.

Richard MacCutchan

Да, спасибо, что заметили.

Michael Haephrati

Это ваше решение??? вопрос в том, как такие необработанные данные могут быть преобразованы в компоненты электронной почты, такие как встроенные фотографии, вложения и т. д.

Richard MacCutchan

Изображения, вложения и т. д. Обычно преобразуются в кодировку base64. Как уже упоминалось мной и Йохеном, вся эта информация находится в свободном доступе. Возможно, вы могли бы показать часть своего кода и объяснить, в чем именно заключается ваша проблема.

Michael Haephrati

Я обновил вопрос с моим недавним исходным кодом. Этот исходный код исходит из того, что szMailBody содержит необработанные данные электронной почты и использует mimelib (https://www.codeproject.com/KB/cpp/1114232/mimelib.zip ) я пытаюсь извлечь из необработанных данных все элементы (встроенные изображения, HTML-тело, вложения и т. д.), предполагая, что это можно сделать статически, то есть без необходимости какого-либо взаимодействия с сервером Gmail.
Проблема в том, что я ожидаю, что содержимое будет содержать все элементы, но это не так.