C++ にて VMime を使って ファイルからメールを読む
の続きです。
添付ファイル付きのメールの構造
下記のように、multipartの中に本文と添付ファイルのデータがある。
Content-Type: multipart/mixed;
Content-Type: text/plain; charset=us-ascii
本文のデータContent-Type: image/png
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename=sample.png;
添付ファイルのデータ
メールメッセージから添付ファイルを取得する
下記は、VMime Book に掲載されている例
添付ファイルの操作:添付ファイルヘルパー
https://ken-ohwada.hatenadiary.org/entry/2020/12/30/160715#53
メッセージからすべての添付ファイルを抽出する例
vmime: : shared ptr <vmime: : message> msg; // suppose we have a message const std::vector <ref <const attachment>> atts = attachmentHelper::findAttachmentsInMessage(msg);
この例のままだと下記のエラーになる。
template argument for template type
parameter must be a type
API 仕様と見比べると、誤記みたいだ。
vmime : attachmentHelper Class Reference
https://www.vmime.org/public/documentation/doxygen/classvmime_1_1attachmentHelper.html
下記のようにするとよい。
const std::vector< vmime::shared_ptr< const vmime::attachment > > atts = vmime::attachmentHelper::findAttachmentsInMessage(msg);
findAttachmentsInMessage の不具合
本文のパートも添付ファイルとみなされる。
対処療法として、ファイル名のあるなしを判定材料とする。
下記のようにファイル名のあるパートだけを取得する。
std::vector< vmime::shared_ptr< const vmime::attachment > > atts1 = vmime::attachmentHelper::findAttachmentsInMessage(msg); std::vector< vmime::shared_ptr< const vmime::attachment > > atts2; for(auto att: atts1){ std::string name = att->getName().getBuffer(); if ( name.length() > 0 ) { atts2.push_back(att); } }
添付ファイルをファイルに保存する
下記のようにする
vmime::string name = att->getName().getBuffer(); std::ofstream ofs; ofs.open( name, ( std::ios_base::out | std::ios_base::binary) ); vmime::utility::outputStreamAdapter file(ofs); vmime::shared_ptr< const vmime::contentHandler > ch = att->getData(); ch->extract(file);
本文を表示する
C++ にて VMime を使って ファイルからメールを読む
で紹介した下記の方法では、本文を取得できない。
vmime::shared_ptr <vmime::body> body = msg->getBody();
この方法で取得した body はマルチパート部全体である。
ここから本文を取得する。
マルチパート部の中の個々のパートは vmime::bodyPart というクラスになる。
vmime bodyPart Class Reference
https://www.vmime.org/public/documentation/doxygen/classvmime_1_1bodyPart.html
bodyPart は下記のように取得する。
vmime::shared_ptr <vmime::body> body = msg->getBody(); size_t count = body->getPartCount(); for(int i=0; i<count; i++){ vmime::shared_ptr<vmime::bodyPart> part = body->getPartAt(i);
bodyPart は、本文とは限らず 添付ファイルの場合もある。
本文か添付ファイルかは、ContentDisposition で区別する。
本文のときは inline で、添付ファイルのときは attachment である。
bodyPart から ContentDisposition は下記のように取得する。
vmime::shared_ptr< vmime::header > part_hdr = part->getHeader(); vmime::shared_ptr< const vmime::headerField > hdr_disposition = hdr->ContentDisposition(); vmime::shared_ptr< const vmime::contentDisposition > disposition = hdr_disposition->getValue<vmime::contentDisposition>(); std::string name = disposition->getName();
bodyPart から 本文は下記のように取得する。
まず vmime::body を取得する。
vmime::shared_ptr< vmime::body > part_body = part->getBody();
vmime::body から本文の取得は、
C++ にて VMime を使って ファイルからメールを読む
と同じ方法でよい。
vmime::utility::outputStreamStringAdapter out(std::cout); vmime::shared_ptr<const vmime::contentHandler> cts = part_body->getContents(); cts->extract(out);
全体のコードは、githubに公開した。
https://github.com/ohwada/MAC_cpp_Samples/tree/master/vmime/read