2011年2月20日日曜日

Gmailの内容をIMAPで取得する LumiSoft.Net編

前回のGmailの内容をIMAPで取得する ImapX編に引き続き、今回は下記ライブラリを使用してGmailの内容を取得する方法を解説する。

LumiSoft.Net
LumiSoft Forum
Source code
Examples

ImapXに比べてこなれていないObject Modelなのでとっつきにくいけれど、慣れればImapX以上の柔軟さがあるし、何よりOSSなので自分で問題解決できるのが良い。

コードはこんな感じ。
// すべてのメールを取得する
try
{
    using (var imap = new IMAP_Client())
    {
        imap.Logger = new Logger();
        imap.Logger.WriteLog += (s, e) => Console.WriteLine(e.LogEntry.Text);
        imap.Connect("imap.gmail.com", 993, true);
        imap.Login("username", "password");
        imap.SelectFolder("INBOX");

        var fetchHandler = new IMAP_Client_FetchHandler();
        fetchHandler.NextMessage += (s, e) =>
        {
            // 次のメッセージ
            Console.WriteLine("");
            Console.WriteLine("");
            Console.WriteLine("New message");
        };
        fetchHandler.Envelope += (s, e) =>
        {
            // To, Fromとか
            Console.WriteLine("Envelope");
            var envelope = e.Value;
            var from = "";
            if (envelope.From != null)
                from = envelope.From.ToList().Select(x => x.ToString()).Aggregate((x, y) => string.Format("{0};{1}", x, y));
            else
                from = "none";

            Console.WriteLine(from);
            var subject = envelope.Subject ?? "none";
            Console.WriteLine(subject);
        };
        fetchHandler.Flags += (s, e) =>
        {
            // フラグ(SEEN, UNSEENとか)
            e.Value.ToList().ForEach(f => Console.WriteLine(f));
        };
        fetchHandler.InternalDate += (s, e) =>
        {
            // 日付
            Console.WriteLine(e.Value.ToString());
        };
        fetchHandler.Rfc822Size += (s, e) =>
        {
            // サイズ
            Console.WriteLine(((decimal)(e.Value / (decimal)1000)).ToString("f2") + " kb");
        };
        fetchHandler.UID += (s, e) =>
        {
            // メールID
            Console.WriteLine(e.Value);
        };

        var sequence = new IMAP_SequenceSet();
        sequence.Parse("1:*");  // 取得する範囲を指定する
        // ※メールが15通あるとして
        // 2,4:7,9,12:*を指定すると
        // 2,4,5,6,7,9,12,13,14,15の順番のメールが取得できる
        // 詳細はIMAP_SequenceSetを参照のこと

        // 第一引数は指定のsequenceがUIDかどうかの判定用。UIDを指定する場合もIMAP_SequenceSetの記述は変わらない
        // 第三引数に指定したものがサーバーから取得され、値の解析後、fetchHandlerがコールバックされる
        imap.Fetch(false, sequence, new IMAP_Fetch_DataItem[]
                                                            {
                                                                new IMAP_Fetch_DataItem_Envelope(),
                                                                new IMAP_Fetch_DataItem_Flags(),
                                                                new IMAP_Fetch_DataItem_InternalDate(),
                                                                new IMAP_Fetch_DataItem_Rfc822Size(),
                                                                new IMAP_Fetch_DataItem_Uid()
                                                            }, fetchHandler);
    }
}
catch (Exception x)
{
    Console.WriteLine(string.Format("IMAP server returned : {0}", x.Message));
}

一見して分かる通りかなり癖があるのでとっつきにくい部分もあるが、慣れてしまえば細かいところまで制御できるので非常に有用だ。

もうひとつサンプルとして未読メッセージのみ取得する方法を紹介しておく。
try
{
    using (var imap = new IMAP_Client())
    {
        imap.Logger = new Logger();
        imap.Logger.WriteLog += (s, e) => Console.WriteLine(e.LogEntry.Text);
        imap.Connect("imap.gmail.com", 993, true);
        imap.Login("username", "password");
        imap.SelectFolder("INBOX");
        
        // 未読のものだけ取得
        var unseenMessages = imap.Search(false, "", "unseen");
        unseenMessages.ToList().ForEach(uid =>
        {
            var seqSet = new IMAP_SequenceSet();
            seqSet.Parse(uid.ToString());

            // Bodyのみハンドル
            var fetchHandler = new IMAP_Client_FetchHandler();
            fetchHandler.Rfc822 += (s, e) =>
            {
                var storeStream = new MemoryStream();
                e.Stream = storeStream;
                e.StoringCompleted += (s2, e2) =>
                {
                    storeStream.Position = 0;
                    var mime = Mail_Message.ParseFromStream(storeStream);

                    Console.WriteLine("Attachment");
                    foreach (var entity in mime.Attachments)
                    {
                        if (entity.ContentDisposition != null && entity.ContentDisposition.Param_FileName != null)
                        {
                            // 添付ファイルの保存
                            var path = Path.Combine(@"C:\", entity.ContentDisposition.Param_FileName);
                            File.WriteAllBytes(path,((MIME_b_SinglepartBase)entity.Body).Data);
                            Console.WriteLine(string.Format("{0} saved", entity.ContentDisposition.Param_FileName));
                        }
                        else
                        {
                            Console.WriteLine("untitled");
                        }
                    }

                    if (mime.BodyText != null)
                        Console.WriteLine(mime.BodyText);

                     // おまけ
                     // テスト用に今回の処理で既読メールになったのを未読メールに戻す
                     imap.StoreMessageFlags(true, seqSet, IMAP_Flags_SetType.Replace, IMAP_MessageFlags.Recent);
                };                
            };

            imap.Fetch(true, seqSet,
                new IMAP_Fetch_DataItem[]
                    {
                        new IMAP_Fetch_DataItem_Rfc822()
                    },fetchHandler);
        });
    }
}
catch (Exception x)
{
    Console.WriteLine(string.Format("IMAP server returned : {0}", x.Message));
}

0 件のコメント:

コメントを投稿