In addition to your thread at the mentioned article which seems to have solved your problem and to have an answer here:
There are no Gmail specific "raw" data. It is the format of mail messages as defined by
RFC 2822: Internet Message Format[
^] and related RFCs like RFC 2045 - 2049 for the MIME extensions.
Those RFCs contain the necessary information to write a parser.
[EDIT]
Example code using the
mimelib.h file from the mentioned article. Compiled and tested with VS 2017. Requires
/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");
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())
{
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;
}
vector<char> partData;
c.DecodeData(partData);
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
{
auto data = c.GetData();
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;
}
Example output for a multipart mail:
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
[/EDIT]