MicrosoftOutlookのメールをRuby(win32ole)で操作する! その2

[Windows][Ruby]MicrosoftOutlookのメールをRuby(win32ole)で操作する! その2

前回までのあらすじ

http://d.hatena.ne.jp/kk_Ataka/20110517/1305560776:title

あれから色々変えたので追記。前回のTODOは…

  1. フォルダ名先頭にYYYYMMDD
  2. フォルダ名に使用できない文字を全角に置換
  3. フォルダ存在時の対処
  4. デスクトップに保存したい

全部消化。とりあえずOutlook開いて添付ファイル付きのメールファイルをデスクトップに保存するだけの簡単なお仕事はできるようになりました!やった!

GitHub

[https://github.com/gosyujin/outlook_for_ruby:title]

なにやってるかの流れ

  • まず初期化。
    # MicrosoftOutlookに接続後初期化処理を行う。
    # MicrosoftOutlookが起動していないと終了する。
    def initialize
        begin
            ol = WIN32OLE::connect("Outlook.Application")
        rescue WIN32OLERuntimeError
            putsError("MicrosoftOutlookが起動していません。")
            exit
        else
            desktopJa = Kconv.tosjis("デスクトップ")
            # NameSpace取得(getNameSpaceの引数は"MAPI"のみ)
            @nameSpace = ol.getNameSpace("MAPI")
            # 保存パス指定
            @saveRootPath = "#{ENV["USERPROFILE"]}\\" + desktopJa + "\\"
            # 保存パスに作成するディレクトリ作成
            @saveDir = ""
            # フォルダ選択番号、ハッシュ
            @folderNum = -1
            @folder = Hash.new
            # メール選択番号、ハッシュ
            @mailNum = -1
            @mail = Hash.new
            # 取得件数のデフォルト値
            @defaultCount = 20
        end
    end
  • 初期化した後、トップレベル[1]のメールフォルダ全部を取得してます。
  • コマンドから選べるように{num => EntryID}のハッシュを作っておきます。{ “1” => “受信トレイのEntryID” }みたいな。
    # ルートからフォルダの一覧を取得する
    def folders(count=@defaultCount)
        folders = @nameSpace.Folders
        @folderNum = 1
        folders.each do |f|
            if count < @folderNum then
                break
            end
            GC.start
            puts f.Name
            puts "N | CNT | FolderName"
            findFolder(f.EntryId)
        end
    end
    # entoryIdを元にフォルダ名を再帰的に取得する
    def findFolder(entryId, count=@defaultCount)
        folder(entryId).Folders.each do |f|
            if count < @folderNum then
                break
            end
            begin
                puts "#{@folderNum} | " + 
                      "#{f.Items.Count}通 | " + 
                      "#{f.Name}"
                      # + " | #{f.Parent.Name}"
                @folder[@folderNum.to_s] = f.EntryId
                @folderNum += 1
                findFolder(f.EntryId)
            rescue => ex
                putsError(ex)
            end
        end
    end
  • フォルダ一覧から一つ選んだら、そのフォルダ内のメール一覧を取得します。
  • これもコマンドから選べるように{num => EntryID}のハッシュを作っておきます。{ “1” => “とあるメールのEntryID” }みたいな。
    # entryIdを元に対象フォルダのメール一覧を取得する
    def mails(entryId, count=@defaultCount)
        f = @nameSpace.GetFolderFromID(entryId)
        if f.Items.Count == 0 then
            raise "フォルダにメールがありません。"
        end
        @mailNum = 1
        puts "N | A | SentOn              | Name       | Subject"
        f.Items.each do |mail|
            if count < @mailNum then
                break
            end
            GC.start
            puts "#{@mailNum} | " +
                        "#{mail.Attachments.Count} | " +
                        "#{mail.SentOn} | " +
                        "#{mail.SenderName.unpack('A10')} | " +
                        "#{mail.Subject.unpack('A35')}"
            @mail[@mailNum.to_s] = mail.EntryId
            @mailNum += 1
        end
    end
  • なお、メールオブジェクト(MailItem)からは以下のような情報を取得できます。

|*MailItem#Attachments.Count|添付ファイルの数|

|*MailItem#SentOn|送信時間|

|*MailItem#SenderName|送信者名|

|*MailItem#Subject|件名|

|*MailItem#To|送信先|

|*MailItem#CC|CC|

|*MailItem#Body|本文|

  • メール一覧から一つ選んだら、デスクトップにディレクトリを作って、その中にメール本文と添付ファイルを保存します。
    # @saveRootPath下にディレクトリを作成する
    def mkdir(mail)
        # 受信日のYYYYMMDD
        receivedTime = Date.strptime(mail.SentOn, "%Y/%m/%d").strftime("%Y%m%d")
        @saveDir = "#{@saveRootPath}" + 
                                "#{receivedTime}_#{replace(mail.Subject)}\\"
        if !File.exist?(@saveDir) then
            Dir.mkdir(@saveDir)
        end
    end
    # @saveDir下にSubject.txtファイルを作成しメール内容を書きこむ
    def saveMail(mail)
        fullPath = "#{@saveDir}#{self.replace(mail.Subject)}.txt"
        File.open(fullPath, "w") do |file|
            file.write "SENDER      : #{mail.SenderName}" + 
                                    "(#{mail.SenderEmailAddress})\n"
            file.write "TO          : #{mail.To}\n"
            file.write "CC          : #{mail.CC}\n"
            file.write "ReceivedTime: #{mail.SentOn}\n"
            file.write "SUBJECT     : #{mail.Subject}\n"
            file.write "BODY        : \n#{mail.Body}\n"
            #puts "■本文保存    :#{fullPath}"
            puts "■本文保存    :#{self.replace(mail.Subject)}"
        end
    end
    # @saveDir下に添付ファイルを保存する
    def saveFile(mail)
        if mail.Attachments.Count != 0 then
            mail.Attachments.each do |item|
                item.SaveAsFile("#{@saveDir}#{self.replace(item.FileName)}")
                puts "■添付ファイル保存:#{item.FileName}"
                
                # ファイルが.msgだった場合添付ファイルをぶっこぬき
                # フォルダ名も変更
                if item.FileName =~ /.*\.msg/ then 
                    msg = MsgParse.new
                    msg.inputMsg("#{@saveDir}#{self.replace(item.FileName)}")
                    fileName = msg.saveFile(@saveDir)
                    renameFolder(mail, fileName)
                end
            end
        else
            puts "添付ファイルはありません。"
        end
    end
  • Attachmentオブジェクトからは以下のような情報を取得できます。

|*Attachment#SaveAsFile(PATH)|添付ファイルをPATHへ保存|

  • ぶっこぬきのくだりは次回…。

今ソース貼ってたら命名とか特にひどい><

リファクタリングしよー。

[1] デフォルトだと個人用フォルダ、保存フォルダみたいな名前かな。ostファイル単位?

関連記事(この記事の初版より古い記事はリンクがグレーで表示されます)

  1. 2011/09/30 [Java] [Windows] [Ruby] .msgファイルをパースして中から添付ファイルを抜き出す
  2. 2011/09/07 [Ruby] [Redmine] [SQLite3] [Windows] Redmineのプラグイン作成のための備忘録と、時々SQLite3
  3. 2011/08/23 [Ruby] [Windows] MicrosoftOutlookで消せなくなったフォルダをwin32ole経由でRubyから消してみる
  4. 2011/05/17 [Ruby] [Windows] MicrosoftOutlookのメールをRubyで操作する!
  5. 2011/05/01 [Ruby] [Redmine] [Windows] Redmineインストール備忘録(Windows)
  6. 2012/10/01 [Ruby] [Bundle] [Windows] bundle execを省略したいのでバッチを作った(Windows版)
  7. 2012/07/17 [Ruby] [Windows] [Redmine] Windows版Redmineをサービスに登録してブート時に起動させる(宿題あり)
  8. 2012/04/20 [Ruby] [Windows] ZenTestで実行したRSpecの結果をGrowlで通知してくれるようにした
  9. 2012/03/27 [Windows] [Jenkins] [Ruby] simplecovとsimplecov-rcovを使ってJenkinsでカバレッジを確認
  10. 2012/03/20 [Windows] [Jenkins] [Ruby] Windows環境用にrcovをビルドしなおす手順
  11. 2012/02/29 [Ruby] [Rails] [Windows] Rails3レシピブックを読みながらRailsを学ぶ モデル、コントローラ、ビュー、Railsの規約など
  12. 2012/02/28 [Ruby] [Windows] [Rails] Rails3レシピブックを読みながらRailsを学ぶ
  13. 2012/02/20 [Ruby] [Windows] Rubyの実行ファイルを作成するExerbとOcraを試してみた
  14. 2011/12/27 [Evernote] [Ruby] [API] EvernoteのAPIをRubyから叩きたい
  15. 2011/12/26 [Ruby] [Haml] [Sinatra] SinatraでHaml入門