2006-04-29
■[Ruby][WIN32OLE] RubyでNotesのメールを書き出す
職場のメール環境がNotesだったのですが、社外出向することになり、Notesのない環境で過去メールをどうやって参照するのか問題となりました。Notes標準の機能では、本文は書き出せるのですが、添付ファイルが書き出せません。
そこでRubyの登場です。NotesはOLEサーバになっており、WIN32OLEでぐりぐりいじることが可能なのです。
notes.rb
require 'win32ole'
class Log
def initialize(s)
@@logger ||= Proc.new { |x| puts x }
@@logger.call(s)
end
def Log.register_logger(p)
@@logger = p
end
end
class Notes
class Session
def initialize(server, dbname)
@server, @dbname = server, dbname
@session = WIN32OLE.new('Notes.NotesSession') or return nil
@db = @session.GetDatabase(@server, @dbname)
end
# Notes::Documentクラスのイテレータ
def each
all = @db.AllDocuments
doc = all.GetFirstDocument
while doc
yield Notes::Document.new(doc)
doc = all.GetNextDocument(doc)
end
end
include Enumerable
# 添付ファイルをdirに書き出す
def extract_files(dir)
self.each do |doc|
doc.each_attachment do |obj|
name = obj.name
Log.new "\t#{name}"
# 対象外の拡張子をチェックする
ext = File.extname(name).downcase
next if %w(htm html csv pif scr com bat).include?(ext)
# 書き出しメソッドを呼び出し
doc.extract_file(name, "#{dir}/#{name}")
end
end
end
# 添付ファイルをdir/fromに書き出す
def extract_files_by_sender(dir, body_hash = nil)
self.each do |doc|
k = doc.addr(doc.from)
# 本文はハッシュに入れておく
if body_hash
body_hash[k] ||= ""
body_hash[k] << doc.to_s
end
# 出力先の作成
extract_dir = "#{dir}/#{k}"
Dir.mkdir(extract_dir) unless File.exist?(extract_dir)
doc.each_attachment do |obj|
name = obj.name
Log.new "\t#{name}"
ext = File.extname(name).downcase
next if %w(htm html csv pif scr com bat).include?(ext)
doc.extract_file(name, "#{extract_dir}/#{name}")
end
end
end
end
class Document
def initialize(doc)
@doc = doc
end
def each_attachment
a = @doc.Items or return
a.each do |obj|
yield Notes::Attachment.new(obj) if obj.Type == 1084 # ATTACHMENT
end
end
def from; @doc.From[0]; end
def sendto; @doc.SendTo[0]; end
def copyto; @doc.CopyTo[0]; end
def subject; @doc.Subject[0]; end
def posted; @doc.GetItemValue('PostedDate')[0]; end
def body; @doc.GetItemValue('Body'); end
def addr(s)
if m = s.match(/CN=(\w+) (\w+)\/O=(\w+)/)
s = "(#{m[3]}) #{m[2]} #{m[1]}"
elsif m = s.match(/(\w+) (\w+)\/(\w+)/)
s = "(#{m[3]}) #{m[2]} #{m[1]}"
elsif m = s.match(/<([\w.-]+@[\w.-]+)>/)
s = m[1]
elsif m = s.match(/([\w.-]+@[\w.-]+)/)
s = m[1]
elsif s == ''
s = '(unknown)'
end
s
end
def to_s
ret = ["From: #{from}"]
ret << "To: #{sendto}"
ret << "Cc: #{copyto}"
ret << "Subject: #{subject}"
ret << "Date: #{posted}"
ret << ""
ret << body
ret << "\n"
ret.join("\n").gsub("\r", "")
end
def extract_file(name, path)
obj = @doc.GetAttachment(name) or return
begin
obj.ExtractFile(path)
rescue => e
Log.new "**** #{e.message} ****"
end
end
end
class Attachment
def initialize(obj)
@obj = obj
end
def extract_file(path)
@obj.ExtractFile(path)
end
def name
@obj.Values[0]
end
end
end
短いコードなので詳しくは解説しませんが、送信者別にフォルダを作ってそれぞれ本文と添付ファイルを書き出すようになっています。Notes::Document#addrでNotes特有のアドレス表記を若干変換していますがこれはひょっとすると社内仕様かもしれません。
extract-cui.rb
require 'notes'
require 'optparse'
if $0 == __FILE__
opt_hash = Hash.new
opt_hash['dir'] = '.'
ARGV.options do |opt|
opt.on('-d [dir]') { |v| opt_hash['dir'] = v }
opt.on('-s') { |v| opt_hash['same_folder'] = v }
opt.parse!
end
dir = File.expand_path(opt_hash['dir'])
if !File.writable?(dir) || ARGV.size == 0
Log.new "Usage: ruby #{$0} [-s] [-d dir] file [file...]"
exit
end
body_hash = Hash.new
ARGV.each do |arg|
if m = arg.match(/(.*)@(.*)/)
nsf, svr = m[1, 2]
else
nsf, svr = [arg, '']
end
if db = Notes::Session.new(svr, nsf)
Log.new "添付ファイル抽出...(#{arg})"
if opt_hash['same_folder']
db.extract_files(dir)
else
db.extract_files_by_sender(dir, body_hash)
end
end
end
Log.new "本文保存..."
body_hash.each do |k, v|
Log.new "\t#{k}"
File.open("#{dir}/#{k}/mail.txt", "w") do |w|
w.puts v
end
end
Log.new "終了"
end
コマンドライン版のサンプルです。引数はローカル保存した*.nsfファイルです。サーバのメールボックスを直接指定することもできるのですが、危険なのでお勧めしません。^^;VisualuRuby版もあるのですが、省略。
半年以上経つのに何をやっていたかすぐに思い出せましたが、これはRubyだからですねえ。私の場合、PerlやVBAだと先月書いたコードでも思い出せなくなります。
トラックバック - http://d.hatena.ne.jp/jitte/20060429/1146289698
リンク元
- 79 http://aruy.net
- 38 http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rls=GGLD,GGLD:2004-22,GGLD:ja&q=Perl+Notes+GetFirstDocument
- 37 http://aruy.net/archives/125
- 36 http://youichi-kato.cocolog-nifty.com/blog/2007/09/rubynotesjquery_b50f.html
- 29 http://search.yahoo.co.jp/search?p=notes+メール+チェック&ei=UTF-8&pstart=1&fr=slv1-wgt&b=21
- 16 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&hs=skd&q=ruby+win32ole+NOTES&btnG=検索&lr=lang_ja
- 12 http://www.google.co.jp/search?hl=ja&q=ノーツ Initialize&lr=
- 11 http://www.google.co.jp/search?q=notes+メール+書き出し&hl=ja&lr=&start=60&sa=N
- 11 http://www.google.com/search?hl=ja&lr=lang_ja&ie=UTF-8&oe=UTF-8&q=notes+呼び出し excel+ビュー&num=50
- 10 http://www.google.co.jp/search?q=Ruby+Notes&lr=lang_ja&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:ja:official&client=firefox