2018年以降の記事はGitHub Pagesに移行しました

MicrosoftOutlookのメールをRubyで操作する!

あらすじ

  1. 職場のメールはMicrosoftOutlook…添付ファイルとかメール本文を手動で保存するだけの簡単なお仕事がめんどいのでマクロを作った
  2. ある日、なんか共通マクロを適用してくださいねとか通達がきたので適用した(今まで使っていた自分のマクロは退避した)
  3. 新マクロにはご丁寧にパスワードがかけられていた…編集不可/(^o^)\
  4. Outlookからマクロを実行するのは諦めて外部からメールを操作しよう…*1
  5. Rubyでできないかな? …win32oleというものがあるらしい!←今ここ

参考サイト

ドンピシャでした。

やりたい事

  • メール本文を保存したい(ファイル名は件名.txt)
  • 添付ファイルを保存したい(ファイル名は添付ファイル名のまま)
  • 上記のファイルをYYYYMMDD_添付ファイル名(拡張子なし)フォルダの中へ格納
  • 保存場所はマイドキュメントかデスクトップ

こんな感じ

[メール]
件名:subsubject
添付ファイル:tmptmpfile.zip

↓ダウンロード

[マイドキュメント]
└[YYYYMMDD_tmptmpfile]
 ├tmptmpfile.zip
 └subsubject.txt

手順

まずソースはこんな感じ。GitHubは gosyujin/outlook_for_ruby · GitHub

# -*- encoding: UTF-8 -*-
require "win32ole"

# 保存ディレクトリ基準。一応マイドキュメントへ
SaveRootPath = "#{ENV["USERPROFILE"]}\\My Documents"

class Outlook
	def initialize
		# Outlookに接続
		ol = WIN32OLE::connect("Outlook.Application")
		# NameSpace取得(getNameSpaceの引数は"MAPI"のみ)
		@nameSpace = ol.getNameSpace("MAPI")
	end

	# EntryIDを元にメールを取得	
	def mail(entryId)
		item = @nameSpace.GetItemFromID(entryId)
		return item
	end
	
	# メールの一覧を取得
	def mails
		# GetDefaultFolder(6)は受信トレイ
		folder = @nameSpace.GetDefaultFolder(6)
		folder.Items.each do |mail|
			GC.start
			yield mail
		end
	end	
end

outlook = Outlook.new
# メールのタイトル、送信日時、EntryID一欄を表示
outlook.mails do |mail|
	#puts "To     :#{mail.To}"
	puts "#{mail.SentOn} | #{mail.Subject.unpack("a50")}"
	puts "#{mail.EntryID}"
end

# 入力待ち。保存したいメールのEntryIdを貼りつけ
mail = outlook.mail(STDIN.gets.chomp)
#puts mail.Attachments.ole_methods
#puts mail.Attachments.Item(1).ole_methods

# 添付ファイルのファイル名を取得
file = mail.Attachments.Item(1).FileName
# RootPath下に添付ファイル名のディレクトリ作成
SaveDir = "#{SaveRootPath}\\#{file.split(".")[0]}"
Dir.mkdir(SaveDir)

# 添付ファイル保存
mail.Attachments.Item(1).SaveAsFile("#{SaveDir}\\#{file}")

# ディレクトリ下にタイトル.txtファイルを作成し送信者、タイトル、本文を書きこむ
File.open("#{SaveDir}\\#{mail.Subject}.txt", "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"
end

基本的に参考サイトの「Ruby から Outlook を操作する」の章の通りに進めば、まず受信トレイの一覧を取ってこれるまではいけます。詰まったのは添付ファイルの扱い…Attachmentsオブジェクトの扱い方でした。

  • まず、自作のOutlook#mailを呼び出し特定のメールを取得します。(EntryIDを元に)
	# EntryIDを元にメールを取得	
	def mail(entryId)
		item = @nameSpace.GetItemFromID(entryId)
		return item
	end
  • このメールオブジェクトにAttachmentsが。そしてAttachments.Item(number)に添付ファイルが格納されているようです。Itemのnumberは1から始まっている? 0だとエラーが出たような…。
  • Item(number)#FileNameで添付ファイル名が、Item(number)#SaveAsFile(path)で添付ファイルの保存ができました。この辺り。
file = mail.Attachments.Item(1).FileName
# RootPath下に添付ファイル名のディレクトリ作成
SaveDir = "#{SaveRootPath}\\#{file.split(".")[0]}"
Dir.mkdir(SaveDir)

# 添付ファイル保存
mail.Attachments.Item(1).SaveAsFile("#{SaveDir}\\#{file}")

まとめ

  • メール本文を保存したい(ファイル名は件名.txt)
    • とりあえずできた
  • 添付ファイルを保存したい(ファイル名は添付ファイル名のまま)
    • とりあえずできた
  • 上記のファイルをYYYYMMDD_添付ファイル名(拡張子なし)フォルダの中へ格納
    • YYYYMMDD付加はまだ、フォルダはできた
  • 保存場所はマイドキュメントかデスクトップ
    • マイドキュメントに保存はできた

TODO

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

穴だらけだしまだわからない事も多いけど、とりあえず動く所までは行けた! ので続く。

*1:もしかしたらググッたら打開策があるのかもしれない。