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

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

前回までのあらすじ

MicrosoftOutlookのメールをRubyで操作する! - kk_Atakaの日記

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

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

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

なにやってるかの流れ

  • まず初期化。
	# 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ファイル単位?